We can see some configuration information about datasource, sqlmapclienttemplate, and sqlmapclient from the previous "online shop version rebirth series: Automatic injection in spring configurations". Overall, the method is as follows:
1. For a single instance, sqlmapclient only configures the configlocation attribute and does not configure datasource;
Second, configure dynamic datasource and sqlmapclient in sqlmapclienttemplate, and inject sqlmapclienttemplate into Dao;
Third, because the ing between the user and the MySQL database is stored in the Oracle master database, dynamic data sources are not applicable, but are directly injected by configuring sqlmapclient and JNDI datasource;
In this configuration mode, the nullpointerexception message is occasionally reported at the beginning of the application. The stack information is as follows:
Java. lang. nullpointerexception <br/> at com. ibatis. sqlmap. engine. impl. sqlmapsessionimpl. setuserconnection (sqlmapsessionimpl. java: 149) <br/> at org.springframework.orm.ibatis.sqlmapclienttemplate.exe cute (sqlmapclienttemplate. java: 179) <br/> at com.alisoft.eshop.ddb.dao.support.ddbsqlmapclienttemplate.exe cute (ddbsqlmapclienttemplate. java: 86) <br/> at Org. springframework. orm. ibatis. sqlmapclienttemplate. delete (sqlmapclienttemplate. java: 396) <br/> at com. alisoft. eshop. DDB. dao. support. ddbsqlmapclienttemplate. delete (ddbsqlmapclienttemplate. java: 53) <br/> at com. alisoft. c2C. biz. dal. dao. ibatis. ibatismigratedatadao. deletedbfrommysql (ibatismigratedatadao. java: 21) <br/> at com. alisoft. c2C. biz. manager. impl. migrationdataimpl. dodeletefrommysql (migrationdataimpl. java: 170) <br/> at com. alisoft. c2C. biz. manager. impl. migrationdataimpl. migrationdate (migrationdataimpl. java: 69)
At the beginning, we thought it was caused by the time out of the first MySQL database connection, but I thought it was wrong! In this case, the stack information should include timeout-related information, but this information is not available. Let's look at the stack information from sqlmapsessionimpl. the problem was quickly located when the source code was tracked in setuserconnection because sqlmapsession was disabled. Let's take a look at the most critical code first:
Sqlmapsession session = This. sqlmapclient. opensession (); <br/> connection ibatiscon = NULL; <br/> try {<br/> If (logger. isdebugenabled () {<br/> logger. debug ("opened sqlmapsession [" + session + "] For ibatis operation"); <br/>}< br/> connection springcon = NULL; <br/> try {<br/> ibatiscon = session. getcurrentconnection (); <br/> If (ibatiscon = NULL) {<br/> springcon = performanceutils. getconnection (getdatasource (); <br/> session. setuserconnection (springcon); <br/> If (logger. isdebugenabled () {<br/> logger. debug ("obtained JDBC connection [" + springcon + "] For ibatis operation "); <br/>}< br/> else {<br/> If (logger. isdebugenabled () {<br/> logger. debug ("reusing JDBC connection [" + ibatiscon + "] For ibatis operation"); <br/>}< br/> return action. doinsqlmapclient (session); <br/>}< br/> catch (sqlexception ex) {<br/> throw getexceptiontranslator (). translate ("sqlmapclient operation", null, ex); <br/>}< br/> finally {<br/> datasourceutils. releaseconnection (springcon, getdatasource ()); <br/>}< br/> finally {<br/> // only close sqlmapsession if we know we 've actually opened it <br/> // at the present level. <br/> If (ibatiscon = NULL) {<br/> session. close (); <br/>}< br/>}
When tracking the code, we found that the code was actually called multiple times. There was no problem during the first execution, and there was no problem during the second execution. The exception information was actually thrown during the third execution, the direct cause is that the sqlmapsession instance has been closed. The root cause is that it is caused by a single sqlmapclient instance!
In the distributed transformation process, a fixed hash modulo or consistent hash algorithm is not used to avoid strong coupling between user and MySQL database shard information, instead, the user and MySQL database shards are stored persistently in the Oracle database of the master database, and then optimized with the cache. In this way, an application scenario occurs:
When we execute an SQL statement in the MySQL database through ibatis, because we need to obtain the connection through datasource, we may need to first access the Oracle master database to obtain the information of the MySQL database corresponding to the current user, the SQL operations of both are performed through ibatis, so the code we mentioned above will be executed multiple times, and the session will be called in finally after each SQL Execution. close (); the session instance is bound to the current thread, so in fact, the execution of those code segments is the same session;
The root cause of the problem has been found, and the solution is simple: distinguish different sqlmapclients for the jndi datasource and dynamic datasource, that is, configure two separate sqlmapclient instances;