java中insert方法、update方法、delete方法处理流程(下篇)
Configuration的newStatementHandler分析
SimpleExecutor的doUpdate方法上文有分析过:
1 public int doUpdate(MappedStatement ms, Object parameter) throws SQLException { 2 Statement stmt = null; 3 try { 4 Configuration configuration = ms.getConfiguration(); 5 StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null); 6 stmt = prepareStatement(handler, ms.getStatementLog()); 7 return handler.update(stmt); 8 } finally { 9 closeStatement(stmt);10 }11 }
这两天重看第5行的newStatementHandler方法的时候,发现方法上文在这个方法中分析地太简略了,这里过一遍一下Configuration的newStatementHandler方法,方法的实现为:
1 public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {2 StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);3 statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);4 return statementHandler;5 }
第3行的代码是加入插件没什么好看的,看下第2行的代码,StatementHandler接口真正实例化出来的是RoutingStatementHandler,构造方法实现为:
1 public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { 2 3 switch (ms.getStatementType()) { 4 case STATEMENT: 5 delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); 6 break; 7 case PREPARED: 8 delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql); 9 break;10 case CALLABLE:11 delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);12 break;13 default:14 throw new ExecutorException("Unknown statement type: " + ms.getStatementType());15 }16 17 }
RoutingStatementHandler同样是装饰器模式的实现,实现了StatementHandler接口并持有StatementHandler接口引用delegate。这里StatementType的为PREPARED,因此执行的第7行的判断,实例化出PreparedStatementHandler,实例化的过程为:
1 protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { 2 this.configuration = mappedStatement.getConfiguration(); 3 this.executor = executor; 4 this.mappedStatement = mappedStatement; 5 this.rowBounds = rowBounds; 6 7 this.typeHandlerRegistry = configuration.getTypeHandlerRegistry(); 8 this.objectFactory = configuration.getObjectFactory(); 9 10 if (boundSql == null) { // issue #435, get the key before calculating the statement11 generateKeys(parameterObject);12 boundSql = mappedStatement.getBoundSql(parameterObject);13 }14 15 this.boundSql = boundSql;16 17 this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);18 this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);19 }
这里的重点是BoundSql,它可以通过MappedStatement获取到,BoundSql中存储了几个重要的内容:
参数对象本身
参数列表
待执行的SQL语句
有些基于MyBatis二次开发的框架通常都会拿到BoundSql中的SQL语句进行修改并重新设置进BoundSql中。
生成Statement
上文已经写了生成Connection的流程,本文继续看,首先还是再贴一下SimpleExecutor的prepareStatement方法:
1 private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {2 Statement stmt;3 Connection connection = getConnection(statementLog);4 stmt = handler.prepare(connection, transaction.getTimeout());5 handler.parameterize(stmt);6 return stmt;7 }
接着就是第4行的代码,生成Statement了,第4行的代码实现为:
Statement prepare(Connection connection, Integer transactionTimeout)
delegate上文是装饰器模式中的被装饰角色,其接口类型为StatementHandler,真实类型为PreparedStatementHandler,这个在最开头的部分已经分析过了。看一下prepare方法实现:
1 public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException { 2 ErrorContext.instance().sql(boundSql.getSql()); 3 Statement statement = null; 4 try { 5 statement = instantiateStatement(connection); 6 setStatementTimeout(statement, transactionTimeout); 7 setFetchSize(statement); 8 return statement; 9 } catch (SQLException e) {10 closeStatement(statement);11 throw e;12 } catch (Exception e) {13 closeStatement(statement);14 throw new ExecutorException("Error preparing statement. Cause: " + e, e);15 }16 }
第6行的代码设置的是查询超时时间、第7行的代码设置的是接收的数据大小,就不跟进去看了,接着看下第6行的instantiateStatement方法实现:
1 protected Statement instantiateStatement(Connection connection) throws SQLException { 2 String sql = boundSql.getSql(); 3 if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) { 4 String[] keyColumnNames = mappedStatement.getKeyColumns(); 5 if (keyColumnNames == null) { 6 return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS); 7 } else { 8 return connection.prepareStatement(sql, keyColumnNames); 9 }10 } else if (mappedStatement.getResultSetType() != null) {11 return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);12 } else {13 return connection.prepareStatement(sql);14 }15 }
第2行,从boundSql中获取真正的SQL语句,第一部分已经分析过了。拿到SQL语句之后,执行第3行与第5行的判断,这里就是我们熟悉的通过Connection拿Statement的代码了,通过prepareStatement方法获取到PreparedStatement,其真实类型为com.mysql.jdbc.JDBC4PreparedStatement,是PreparedStatement的子类。
Statement参数设置
获取了Statement后,下一步就是设置参数了,看一下设置参数的代码,还是回到SimpleExecutor的prepareStatement方法:
1 private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {2 Statement stmt;3 Connection connection = getConnection(statementLog);4 stmt = handler.prepare(connection, transaction.getTimeout());5 handler.parameterize(stmt);6 return stmt;7 }
跟第5行的代码:
1 public void parameterize(Statement statement) throws SQLException { 2 parameterHandler.setParameters((PreparedStatement) statement); 3 }
继续跟第2行的代码:
1 public void setParameters(PreparedStatement ps) { 2 ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId()); 3 List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); 4 if (parameterMappings != null) { 5 for (int i = 0; i < parameterMappings.size(); i++) { 6 ParameterMapping parameterMapping = parameterMappings.get(i); 7 if (parameterMapping.getMode() != ParameterMode.OUT) { 8 Object value; 9 String propertyName = parameterMapping.getProperty();10 if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params11 value = boundSql.getAdditionalParameter(propertyName);12 } else if (parameterObject == null) {13 value = null;14 } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {15 value = parameterObject;16 } else {17 MetaObject metaObject = configuration.newMetaObject(parameterObject);18 value = metaObject.getValue(propertyName);19 }20 TypeHandler typeHandler = parameterMapping.getTypeHandler();21 JdbcType jdbcType = parameterMapping.getJdbcType();22 if (value == null && jdbcType == null) {23 jdbcType = configuration.getJdbcTypeForNull();24 }25 try {26 typeHandler.setParameter(ps, i + 1, value, jdbcType);27 } catch (TypeException e) {28 throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);29 } catch (SQLException e) {30 throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);31 }32 }33 }34 }35 }
最终执行的是第26行的代码,从26行的代码我们可以知道,参数设置到最后都是通过参数的TypeHandler来执行的,JDBC为我们预定义了很多TypeHandler,比如int值的TypeHandler就是IntegerTypeHandler,当然我们也可以定义自己的TypeHandler,通常来说继承BaseTypeHandler就可以了。
但是在此之前,会获取到Statement(setParameters方法形参)、占位符位置号(for循环的遍历参数i)、参数值(通过属性名获取)与jdbcType(配置在配置文件中,默认为null),最终执行TypeHandler的setParameters方法,这是BaseTypeHandler中的一个方法:
1 public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException { 2 if (parameter == null) { 3 if (jdbcType == null) { 4 throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters."); 5 } 6 try { 7 ps.setNull(i, jdbcType.TYPE_CODE); 8 } catch (SQLException e) { 9 throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " +10 "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " +11 "Cause: " + e, e);12 }13 } else {14 try {15 setNonNullParameter(ps, i, parameter, jdbcType);16 } catch (Exception e) {17 throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . " +18 "Try setting a different JdbcType for this parameter or a different configuration property. " +19 "Cause: " + e, e);20 }21 }22 }
这里的参数不为null,走13行的else,执行setNonNullParameter方法,这是IntegerTypeHandler中的一个方法:
setNonNullParameter(PreparedStatement ps,
这里的代码就比较熟悉了,PreparedStatement的setInt方法。
执行更新操作并处理结果
最后一步,执行更新操作并对结果进行处理,回到SimpleExecuto的doUpdate方法:
1 public int doUpdate(MappedStatement ms, Object parameter) throws SQLException { 2 Statement stmt = null; 3 try { 4 Configuration configuration = ms.getConfiguration(); 5 StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null); 6 stmt = prepareStatement(handler, ms.getStatementLog()); 7 return handler.update(stmt); 8 } finally { 9 closeStatement(stmt);10 }11 }
第6行已经准备好了Statement,第7行执行update操作并对结果进行处理并返回:
update(Statement statement)
这里的委托delegate前面已经说过了,其真实类型是PreparedStatementHandler,update方法的实现为:
1 public int update(Statement statement) throws SQLException {2 PreparedStatement ps = (PreparedStatement) statement;3 ps.execute();4 int rows = ps.getUpdateCount();5 Object parameterObject = boundSql.getParameterObject();6 KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();7 keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);8 return rows;9 }
第3行的execute方法是PreparedStatement中的方法,execute方法执行操作,然后第4行通过getUpdateCount()方法获取本次操作更新了几条数据,作为最终的值返回给用户。
第5行的代码通过BoundSql获取参数对象,这里是MailDO对象,因为我们知道在插入场景下,开发者是有这种需求的,需要返回插入的主键id,此时会将主键id设置到MailDO中。
第6行的代码通过MappedStatement获取KeyGenerator,一个主键生成器。
第7行的代码做了一个操作完毕的后置处理:
<span style="color: #008080"> 1</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {</span><span style="color: #008080"> 2</span> <span style="color: #000000"> processBatch(ms, stmt, getParameters(parameter));</span><span style="color: #008080"> 3</span> <span style="color: #000000">}</span><span style="color: #008080"><br/></span>
首先将对象包装成集合类型,然后跟第2行的代码processBatch方法:
1 public void processBatch(MappedStatement ms, Statement stmt, Collection<Object> parameters) { 2 ResultSet rs = null; 3 try { 4 rs = stmt.getGeneratedKeys(); 5 final Configuration configuration = ms.getConfiguration(); 6 final TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); 7 final String[] keyProperties = ms.getKeyProperties(); 8 final ResultSetMetaData rsmd = rs.getMetaData(); 9 TypeHandler<?>[] typeHandlers = null;10 if (keyProperties != null && rsmd.getColumnCount() >= keyProperties.length) {11 for (Object parameter : parameters) {12 // there should be one row for each statement (also one for each parameter)13 if (!rs.next()) {14 break;15 }16 final MetaObject metaParam = configuration.newMetaObject(parameter);17 if (typeHandlers == null) {18 typeHandlers = getTypeHandlers(typeHandlerRegistry, metaParam, keyProperties, rsmd);19 }20 populateKeys(rs, metaParam, keyProperties, typeHandlers);21 }22 }23 } catch (Exception e) {24 throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e, e);25 } finally {26 if (rs != null) {27 try {28 rs.close();29 } catch (Exception e) {30 // ignore31 }32 }33 }34 }
简单说这里就是遍历集合,通过JDBC4PreparedStatement的getGeneratedKeys获取ResultSet,然后从ResultSet中使用getLong方法获取生成的主键,设置到MailDO中。完成整个操作。
最后,本文演示的是insert数据的update方法流程,前文已经说过insert、update、delete在MyBatis中都是一样的,因此update、delete也是一样的操作,这里就不再赘述了。
Atas ialah kandungan terperinci java中insert方法、update方法、delete方法处理流程(下篇). Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas



Novel Tomato adalah perisian membaca novel yang sangat popular Kami sering mempunyai novel dan komik baru untuk dibaca dalam Novel Tomato Setiap novel dan komik sangat menarik ingin menulis ke dalam teks. Jadi bagaimana kita menulis novel di dalamnya? Kongsi tutorial novel Tomato tentang cara menulis novel 1. Mula-mula buka aplikasi novel percuma Tomato pada telefon bimbit anda dan klik pada Pusat Peribadi - Pusat Penulis 2. Lompat ke halaman Pembantu Penulis Tomato - klik pada Buat buku baru di penghujung novel.

Papan induk berwarna-warni menikmati populariti tinggi dan bahagian pasaran dalam pasaran domestik China, tetapi sesetengah pengguna papan induk Berwarna-warni masih tidak tahu cara memasukkan bios untuk tetapan? Sebagai tindak balas kepada situasi ini, editor telah membawakan anda secara khas dua kaedah untuk memasukkan bios motherboard yang berwarna-warni. Datang dan cuba! Kaedah 1: Gunakan kekunci pintasan permulaan cakera U untuk terus memasuki sistem pemasangan cakera U Kekunci pintasan untuk papan induk Berwarna untuk memulakan cakera U dengan satu klik ialah ESC atau F11 Pertama, gunakan Black Shark Installation Master untuk mencipta Black Cakera but cakera Shark U, dan kemudian hidupkan komputer Apabila anda melihat skrin permulaan, tekan terus kekunci ESC atau F11 pada papan kekunci untuk memasuki tetingkap untuk pemilihan item permulaan secara berurutan ke tempat "USB " dipaparkan, dan kemudian

Malangnya, orang sering memadamkan kenalan tertentu secara tidak sengaja atas sebab tertentu WeChat ialah perisian sosial yang digunakan secara meluas. Untuk membantu pengguna menyelesaikan masalah ini, artikel ini akan memperkenalkan cara mendapatkan semula kenalan yang dipadam dengan cara yang mudah. 1. Fahami mekanisme pemadaman kenalan WeChat Ini memberi kita kemungkinan untuk mendapatkan semula kenalan yang dipadamkan Mekanisme pemadaman kenalan dalam WeChat mengalih keluar mereka daripada buku alamat, tetapi tidak memadamkannya sepenuhnya. 2. Gunakan fungsi "Pemulihan Buku Kenalan" terbina dalam WeChat menyediakan "Pemulihan Buku Kenalan" untuk menjimatkan masa dan tenaga Pengguna boleh mendapatkan semula kenalan yang telah dipadamkan dengan cepat melalui fungsi ini. 3. Masuk ke halaman tetapan WeChat dan klik sudut kanan bawah, buka aplikasi WeChat "Saya" dan klik ikon tetapan di sudut kanan atas untuk memasuki halaman tetapan.

Menetapkan saiz fon telah menjadi keperluan pemperibadian yang penting kerana telefon mudah alih menjadi alat penting dalam kehidupan seharian manusia. Untuk memenuhi keperluan pengguna yang berbeza, artikel ini akan memperkenalkan cara meningkatkan pengalaman penggunaan telefon mudah alih dan melaraskan saiz fon telefon mudah alih melalui operasi mudah. Mengapa anda perlu melaraskan saiz fon telefon mudah alih anda - Melaraskan saiz fon boleh menjadikan teks lebih jelas dan mudah dibaca - Sesuai untuk keperluan membaca pengguna yang berbeza umur - Mudah untuk pengguna yang kurang penglihatan menggunakan saiz fon fungsi tetapan sistem telefon mudah alih - Cara memasukkan antara muka tetapan sistem - Dalam Cari dan masukkan pilihan "Paparan" dalam antara muka tetapan - cari pilihan "Saiz Fon" dan laraskan saiz fon dengan pihak ketiga aplikasi - muat turun dan pasang aplikasi yang menyokong pelarasan saiz fon - buka aplikasi dan masukkan antara muka tetapan yang berkaitan - mengikut individu

Permainan mudah alih telah menjadi sebahagian daripada kehidupan orang ramai dengan perkembangan teknologi. Ia telah menarik perhatian ramai pemain dengan imej telur naga yang comel dan proses penetasan yang menarik, dan salah satu permainan yang telah menarik perhatian ramai ialah versi mudah alih Dragon Egg. Untuk membantu pemain memupuk dan mengembangkan naga mereka sendiri dengan lebih baik dalam permainan, artikel ini akan memperkenalkan kepada anda cara menetas telur naga dalam versi mudah alih. 1. Pilih jenis telur naga yang sesuai Pemain perlu berhati-hati memilih jenis telur naga yang mereka suka dan sesuai dengan diri mereka, berdasarkan pelbagai jenis sifat dan kebolehan telur naga yang disediakan dalam permainan. 2. Tingkatkan tahap mesin pengeraman Pemain perlu meningkatkan tahap mesin pengeraman dengan menyelesaikan tugasan dan mengumpul prop Tahap mesin pengeraman menentukan kelajuan penetasan dan kadar kejayaan penetasan. 3. Kumpul sumber yang diperlukan untuk penetasan Pemain perlu berada dalam permainan

Dalam masyarakat hari ini, telefon bimbit telah menjadi sebahagian daripada kehidupan kita. Sebagai alat penting untuk komunikasi harian, kerja dan kehidupan kita, WeChat sering digunakan. Walau bagaimanapun, mungkin perlu untuk memisahkan dua akaun WeChat apabila mengendalikan transaksi yang berbeza, yang memerlukan telefon mudah alih untuk menyokong log masuk ke dua akaun WeChat pada masa yang sama. Sebagai jenama domestik yang terkenal, telefon bimbit Huawei digunakan oleh ramai orang Jadi apakah kaedah untuk membuka dua akaun WeChat pada telefon bimbit Huawei? Mari kita dedahkan rahsia kaedah ini. Pertama sekali, anda perlu menggunakan dua akaun WeChat pada masa yang sama pada telefon mudah alih Huawei anda Cara paling mudah ialah

Perbezaan antara kaedah dan fungsi bahasa Go terletak pada perkaitannya dengan struktur: kaedah dikaitkan dengan struktur dan digunakan untuk mengendalikan data struktur atau fungsi adalah bebas daripada jenis dan digunakan untuk melaksanakan operasi umum.

Filem telefon bimbit telah menjadi salah satu aksesori yang sangat diperlukan dengan populariti telefon pintar. Untuk memanjangkan hayat perkhidmatannya, pilih filem telefon mudah alih yang sesuai untuk melindungi skrin telefon mudah alih. Untuk membantu pembaca memilih filem telefon bimbit yang paling sesuai untuk diri mereka sendiri, artikel ini akan memperkenalkan beberapa perkara utama dan teknik untuk membeli filem telefon bimbit. Fahami bahan dan jenis filem telefon bimbit: Filem PET, TPU, dsb. Filem telefon mudah alih diperbuat daripada pelbagai bahan, termasuk kaca terbaja. Filem PET agak lembut, filem kaca terbaja mempunyai rintangan calar yang baik, dan TPU mempunyai prestasi kalis kejutan yang baik. Ia boleh diputuskan berdasarkan keutamaan dan keperluan peribadi semasa memilih. Pertimbangkan tahap perlindungan skrin Jenis filem telefon mudah alih yang berbeza mempunyai tahap perlindungan skrin yang berbeza. Filem PET terutamanya memainkan peranan anti-calar, manakala filem kaca terbaja mempunyai rintangan jatuh yang lebih baik. Anda boleh memilih untuk menjadi lebih baik
