Skenario pembuatan pengecualian dan informasi pengecualian
Pekan lalu, pengecualian terjadi karena kelas generik yang mengimplementasikan antarmuka Peta. Enterry digunakan dalam metode antarmuka mapper MyBatis, dan pernyataan SQL yang sesuai dengan metode ini juga menggunakan tag foreach. Berikut ini adalah informasi pengecualian:
org.apache.ibatis.exceptions.persistenceException: ### kesalahan pembaruan database. Penyebab: org.apache.atisis.reflection.reflectionException: Tidak ada pengambil untuk properti bernama 'kunci' di 'kelas java.lang.integer' ### kesalahan mungkin melibatkan org.sertbatching.test.spring.server.goodsroomnight3dsmapper.insertbatching. Goods_roomnight_30Days (Goods_id, checkin_room_night_30days) nilai (?,?), (?,?), (?,?), (?,?), (?,?) ### Penyebab: org.apache.hatis.Ibatis.reflection.reflectionException: Tidak ada pengambil properti 'inapache' class 'class' class ' org.apache.ibatis.exceptions.ExceptionFactory.WrapException (ExceptionFactory.java:30) di org.apache.iatis.session.defaults.defaultsqlsession.update (defaultsqlsession.java:200) di org.apache.ibatis.Session.defaults.defaultsqlsession.insert (defaultSqlsession.java:185) di org.apache.ibatis.binding.mappermethod.execute (mappermethod.java:57) di org.apache.ibatis.binding.mapperproxy.invoke (mapperproxy.java:53) di com.sun.proxy. $ proxy4.insertbatch (sumber yang tidak diketahui) di org.test.test.test.spring.server.goodsroomroomnight.test.test. sun.reflect.nativeMethodaccessorImpl.invoke0 (metode asli) di sun.reflect.nativeMethodacessorimpl.invoke (nativeMethoDacCessorImpl.java:57) di sun.reflect.delegatingmethodacessempl.invoke (delegatingmethlect. java.lang.reflect.method.invoke (method.java:606) di org.junit.runners.model.frameworkmethod $ 1.runreflectiveCall (frameworkmethod.java:47) di org.junit.internal.runners.model.reflectiveCallable.run (reflectiveCallable.java:12) di org.junit.runners.model.frameworkmethod.invokeExplosive (FrameworkMethod.java:44) di org.junit.internal.runners.statements.invokemethod.evaluate (Invokemethod.java:17) di org.junit.internal.runners.statements.runbefores.evaluate (runbefores.java:26) di org.junit.internal.runners.Statements.runaafters.evaluate (runafters.java:27) di org.junit.runners.parentrunner.runleaf (parentrunner.java:271) org.junit.runners.blockjunit4classrunner.runchild (blockjunit4classrunner.java:70) di org.junit.runners.blockjunit4classrunner.runchild (blockjunit4classrunner.java:50) di org.junit.runners.parentrunner $ 3.run (parentrunner.java:238) di org.junit.runners.parentrunner $ 1.schedule (parentrunner.java:63) di org.junit.runners.parentrunner.runchilren (ParentRner.236 org.junit.runners.parentrunner.access $ 000 (parentrunner.java:53) di org.junit.runners.parentrunner $ 2. evaluati (parentrunner.java:229) di org.junit.runners.parentrunner.runner.runner (Parentrunner.junner.runners.parentrunner.runner.Runner. org.junit.runner.junitcore.run (junitcore.java:160) di com.intellij.junit4.junit4ideatestrunner.Startrunnerwithargs (junit4ideatestrunner.java:68) di com.intellij.rt.execution.junit.ideatestrunner $ repeater.StarTrunnerWithArgs (Ideatestrunner.java:51) di com.intellij.rt.execution.junit.junitstarter.preparestreamsandStart (junitstarter.java:23) com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)Caused by: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'key' in 'class java.lang.Integer' at org.apache.iathis.reflection.reflector.getGetInvoker (reflector.java:409) di org.apache.iatis.reflection.metaclass.getGetInvoker (metaClass.java:164) di org.apache.iatis.reflection.wrapper.beanwrapper.getBeanProperty (beanwrapper.java:162) di org.apache.iatis.reflection.wrapper.beanwrapper.get (beanwrapper.java:49) di org.apache.iathis.reflection.metaobject.getValue (metaObject.java:122) di org.apache.iatis.reflection.metaObject.getValue (metaoBject.java:119) di org.apache.iathis.mapping.boundsql.getAdditionalparameter (boundsql.java:75) di org.apache.iatis.scripting.defaults.defaultparameterhandler.setParameters (defaultparameterhandler.java:72) di org.apache.iathis.executor.statement.PreparedStatementHandler.parameterize (disiapkan statementhandler.java:93) di org.apache.ibatis.executor.statement.Routingstatementhandler.parameterize (routingstatementhandler.java:64) org.apache.ibatis.executor.SimpleExecutor.preparestatement (SimpleExecutor.java:86) di org.apache.iatis.executor.simpleExecutor.doupDate (SimpleExecutor.java:49) di org.apache.ibata.executor.basexecutor.java: di org.apache.ibatis.session.defaults.defaultsqlsession.update (defaultsqlsession.java:198) ... 29 lebih
Karena saya tidak tahu banyak tentang mybatis, saya butuh waktu lama untuk men -debug dan mencari tahu penyebab spesifik kelainan.
Selanjutnya, saya akan mereproduksi pengecualian dan menganalisis penyebab pengecualian.
Pengecualian muncul kembali
Untuk mereproduksi pengecualian di atas, demo ditulis. Kode yang relevan adalah sebagai berikut:
Struktur Tabel Basis Data:
Buat Tabel `Goods_roomnight_30Days` (` Goods_id` Bigint (20) Bukan NULL, `checkin_room_night_30days` int (11) bukan null default '0' komentar 'malam 30 hari terakhir', kunci utama (` goods_id`)) engine = innodb charset default = utf8 komentar = 'barang' terakhir 30-hari 'terakhir'
KEYVALUE.JAVA Parameter Kelas:
KeyValue kelas publik <K, V> mengimplementasikan peta.entry <k, v> {private k key; nilai V pribadi; public keyValue () {} public keyValue (K key, v nilai) {this.key = key; this.value = nilai; } @Override public k getKey () {return key; } @Override public v getValue () {nilai pengembalian; } @Override public v setValue (nilai v) {v oldValue = this.value; this.value = nilai; Kembalikan OldValue; } public jsonObject ToJSonObject () {return ReportJSonObject.newObject (). append (string.valueof (key), value); } @Override public string toString () {return tojsonObject (). TOJSonstring (); }}DAO Class Goodsroomnight3Ddaysmapper.java
antarmuka publik Goodsroomnight3Ddaysmapper {int deleteByExample (Goodsroomnight3DaySexample Contoh); Daftar <Goodsroomnight3ysys> SelectByExample (Contoh Goodsroomnight3DeSexample); <K, v> int insertBatch (daftar <keyvalue <k, v >> catatan);}File mybatis-config.xml:
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration> <settings> <setting name="cacheEnabled" value="false"/> </settings> <!-- After integration with spring, the environments configuration will be abolished and handed over to spring management--> <environments default="development"> <environment id="development"> <!-- Use jdbc transaction management--> <transactionManager type="JDBC" /> <!-- Database connection pool, after integration, third-party connection pools are generally used-> <dataSource type="POOLED"> <property name = "driver" value = "com.mysql.jdbc.driver" /> <name properti = "url" value = "jdbc: mysql: // localhost: 3306 /hotel_report? Karakterencoding = UTF-8" /> <nama properti = "nama pengguna" value = "test_user" /< /> <"name =" "name" name = "name =" name "value =" test_user " /> <" name = "" name "name =" name = "name" value "value =" Test_user " /< /> <" Name "" NAME "" NOVOLE "" NOVORE "NOVOLE" NOVEOME = "NOVOLE" NOVEOME = "Nilai" </urvepers> </surveperments> <mappers> <mapper resource = "mybatis/goodsroomnight3kdaysmapper.xml"/> </phappers> </configuration>
Isi utama Goodsroomnight3Daysmapper.xml File:
<insert id = "insertBatch" parameTerType = "list"> Ganti ke Goods_roomnight_30Days (Goods_id, checkin_room_night_30days) Nilai <foreach collection = "list" index = "index" item = "item" pemisah = ","> ( #{{item.key}, #{item.value}) <! null "> (#{item.key}, 0) </whow>-> <!-<whe test =" item.value! = null "> (#{item.key},#{item.value}) </kapis>-> <!-</toach> </foreach> </incisip>Di atas adalah kode utama untuk mereproduksi pengecualian ini. Kode lengkap dapat dilihat di github: https://github.com/misterzhou/java-demo/tree/master/test-spring/spring-server
Kode Uji yang mereproduksi Exception Goodsroommnight3Ddaystest.java:
Paket org.guojing.test.spring.server; impor org.apache.ibatis.io.Resources; impor org.apache.ibatis.Session.sqlsession; impor org.apache.atis.session.sqlSessionFactory; impor org.apache.ibatis.sesesion org.apache.Ibatis.Session.SQLSessionFactoryBuilder; impor org.guojing.spring.commons.value; impor org.junit.after; impor org.junit.before; impor org.junit.test; impor java.io.ioAcception; impor org.junit.test; impor java.io.io exception; import; java.util.arraylist; import java.util.list;/** * dibuat di: 2016-12-24 * * @author guojing */kelas publik Goodnroomnight3Dsdaystest {sqlSessionFactory sqlSessionFactory; Sqlsession sqlsession; Goodsroomnight3dsmapper Goodsroomnight30smapper; @Before public void init () melempar ioException {String Resource = "mybatis/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsstream (sumber daya); SQLSessionFactory = SQLSessionFactoryBuilder baru (). Build (InputStream); SQLSession = SQLSessionFactory.opensession (true); Goodsroomnight3Daysmapper = SQLSession.getMapper (Goodsroomnight3Ddaysmapper.class); } @Test public void test () {list <keyValue <long, integer >> records = new ArrayList <> (); Records.add (KeyValue baru <Long, Integer> (1725L, 5)); Records.add (KeyValue baru <long, integer> (1728l, 3)); Records.add (KeyValue baru <long, integer> (1730L, null)); Records.add (KeyValue baru <long, integer> (1758l, null)); int deleted = Goodsroomnight3Ddaysmapper.deletyebyexample (Goodsroomroomnight 30DaySexample ()); System.out.println ("----- Ukuran baris yang dihapus:" + dihapus); int row = Goodsroomnight3Ddaysmapper.insertBatch (catatan); System.out.println ("----- Baris yang terpengaruh:" + baris); Daftar <Goodsroomnight3Days> hasil = Goodsroomnight3Thaysmapper.SelectByExample (Goodsroomnightnight3dnaySexample ()); untuk (item Goodsroomnight30sys: hasil) {System.out.println (item.toString ()); }} @After public void after () {if (sqlSession! = Null) {sqlSession.close (); }}}Mari kita merahasiakannya, jangan melihat ke bawah terlebih dahulu, pikirkan tentang penyebab kelainan (siswa yang mahir dalam menggunakan tag foreach harus dapat melihat petunjuknya).
Proses pengecualian dan analisis pengecualian
Dalam proyek, karena kelas parameter dan kelas hasil pengembalian dari metode DAO sering berisi nilai yang sesuai dengan kunci dan kunci, untuk menghindari berulang kali mendefinisikan kelas, saya mendefinisikan kelas generik keyvalue yang mengimplementasikan antarmuka masuk peta. Untuk detailnya, silakan lihat bagian sebelumnya.
Metode GoodsRoomnight30daysMapper.insertBatch() menggunakan kelas generik ini. Setelah berjalan, informasi pengecualian yang disebutkan di awal artikel ini dilemparkan.
Setelah melihat informasi pengecualian, saya fokus pada apakah dukungan MyBatis untuk obat generik tidak cukup baik. Saya bertanya kepada kolega saya (@shengnan), dan kolega saya mencobanya di mesinnya dan menemukan bahwa tidak ada kelainan. Ini aneh. Setelah melihat lebih dekat pada kode, saya menemukan bahwa perbedaannya adalah bahwa kelas generik KeyValue saya mengimplementasikan antarmuka MAP.Entry. Pada saat ini, saya tidak tahu deskripsi tag foreach di situs web resmi Mybatis:
Objek iterable apa pun (seperti daftar, koleksi, dll.) Dan apa pun objek kamus atau array dapat diteruskan ke foreach sebagai parameter koleksi. Saat menggunakan objek atau array yang dapat diulang, indeks adalah berapa kali iterasi, dan nilai item adalah elemen yang diperoleh dalam iterasi ini. Saat menggunakan kamus (atau kumpulan objek MAP.Entry), indeks adalah kunci dan item adalah nilainya.
Selanjutnya, periksa alasan spesifik untuk pengecualian melalui debug. Jadi saya pertama kali menggunakan kode kelas KeyValue yang mengimplementasikan antarmuka MAP.Entry untuk men -debug. Melalui log pengecualian, saya dapat melihat bahwa pengecualian dilemparkan sejalan default sqlsession.java:200, jadi saya menekan breakpoint ke garis default sqlsession.java:197, dan kemudian saya mengeksekusi langkah demi langkah. Ketika saya mengeksekusi untuk melapisi foreachsqlnode.java:73, saya akhirnya menyadarinya. Mari kita lihat diagram rantai panggilan debug terlebih dahulu:
Mari kita lihat kode spesifik foreachsqlnode.java:73 (kelas ini adalah kelas simpul dari objek tag foreach):
Pada saat ini, penyebab spesifik pengecualian sangat jelas. Kelas tempat objek O di sini adalah kelas KeyValue. Karena kelas KeyValue mengimplementasikan antarmuka MAP.Entry, o Instance Map.Entry benar, MyBatis menetapkan nilai kunci ke atribut indeks foreach, dan menetapkan nilai ke atribut item. Di sini, objek integer dengan nilai 5 ditetapkan ke atribut item. Oleh karena itu, objek yang sesuai yang sesuai dengan atribut item dari tag pilih dengan insertBatch di Goodsroomnight3Daysmapper.xml tidak memiliki item.key dan item.value atribut, yang merupakan penyebab akhir dari pengecualian.
<insert id = "insertBatch" parameTerType = "list"> ganti ke goods_roomnight_30 hari (Goods_id, checkin_room_night_30days) Nilai <foreach collection = "list" index = "index" item = "item" pemisah = ","> ( #{item.key}, #{item.value}) </foreach> ( #{{{{/}, #{{{{{{value) </forator> </forator>Di atas adalah analisis singkat tentang alasan mengapa tag Mybatis Foreach digunakan secara tidak benar, dan saya harap ini akan membantu Anda. Jika Anda memiliki pertanyaan, silakan tinggalkan saya pesan dan editor akan membalas Anda tepat waktu. Terima kasih banyak atas dukungan Anda ke situs web Wulin.com!