Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

An example Analysis of Mybatis Spring and Mybatis transaction transaction

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly introduces the example analysis of Mybatis Spring and Mybatis things transaction, the article is very detailed, has a certain reference value, interested friends must read it!

Mybatis-3.4.6.release, mybatis-spring-1.3.2.release.

List-1

Let's take a look at SqlSessionFactoryBean first. Does it need a dataSource, or is it a xml configuration file for mybatis?

The SqlSessionFactoryBean class implements the InitializingBean interface, so if you know SpringIOC, you will know the role of InitializingBean. Let's look at afterPropertiesSet () of InitializingBean. AfterPropertiesSet () calls buildSqlSessionFactory () to generate SqlSessionFactory.

List-2

Protected SqlSessionFactory buildSqlSessionFactory () throws IOException {Configuration configuration; XMLConfigBuilder xmlConfigBuilder = null; if (this.configuration! = null) {configuration = this.configuration; if (configuration.getVariables () = = null) {configuration.setVariables (this.configurationProperties);} else if (this.configurationProperties! = null) {configuration.getVariables () .putAll (this.configurationProperties) }} else if (this.configLocation! = null) {xmlConfigBuilder = new XMLConfigBuilder (this.configLocation.getInputStream (), null, this.configurationProperties); configuration = xmlConfigBuilder.getConfiguration ();} else {if (LOGGER.isDebugEnabled ()) {LOGGER.debug ("Property 'configuration' or' configLocation' not specified, using default MyBatis Configuration");} configuration = new Configuration () If (this.configurationProperties! = null) {configuration.setVariables (this.configurationProperties);}} if (this.objectFactory! = null) {configuration.setObjectFactory (this.objectFactory);} if (this.objectWrapperFactory! = null) {configuration.setObjectWrapperFactory (this.objectWrapperFactory);} if (this.vfs! = null) {configuration.setVfsImpl (this.vfs) } if (hasLength (this.typeAliasesPackage)) {String [] typeAliasPackageArray = tokenizeToStringArray (this.typeAliasesPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); for (String packageToScan: typeAliasPackageArray) {configuration.getTypeAliasRegistry () .registerAliases (packageToScan, typeAliasesSuperType = = null? Object.class: typeAliasesSuperType); if (LOGGER.isDebugEnabled ()) {LOGGER.debug ("Scanned package:'" + packageToScan + "'for aliases");} if (! isEmpty (this.typeAliases)) {for (Class typeAlias: this.typeAliases) {configuration.getTypeAliasRegistry () .registerAlias (typeAlias) If (LOGGER.isDebugEnabled ()) {LOGGER.debug ("Registered type alias:'" + typeAlias + "');} if (! isEmpty (this.plugins)) {for (Interceptor plugin: this.plugins) {configuration.addInterceptor (plugin); if (LOGGER.isDebugEnabled ()) {LOGGER.debug (" Registered plugin:'"+ plugin +") } if (hasLength (this.typeHandlersPackage)) {String [] typeHandlersPackageArray = tokenizeToStringArray (this.typeHandlersPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); for (String packageToScan: typeHandlersPackageArray) {configuration.getTypeHandlerRegistry (). Register (packageToScan); if (LOGGER.isDebugEnabled ()) {LOGGER.debug ("Scanned package:'" + packageToScan + "'for type handlers") } if (! isEmpty (this.typeHandlers)) {for (TypeHandler typeHandler: this.typeHandlers) {configuration.getTypeHandlerRegistry () .register (typeHandler); if (LOGGER.isDebugEnabled ()) {LOGGER.debug ("Registered type handler:'" + typeHandler + "") } if (this.databaseIdProvider! = null) {/ / fix # 64 set databaseId before parse mapper xmls try {configuration.setDatabaseId (this.databaseIdProvider.getDatabaseId (this.dataSource));} catch (SQLException e) {throw new NestedIOException ("Failed getting a databaseId", e);}} if (this.cache! = null) {configuration.addCache (this.cache) } if (xmlConfigBuilder! = null) {try {xmlConfigBuilder.parse (); if (LOGGER.isDebugEnabled ()) {LOGGER.debug ("Parsed configuration file:'" + this.configLocation + "'");}} catch (Exception ex) {throw new NestedIOException ("Failed to parse config resource:"+ this.configLocation, ex) } finally {ErrorContext.instance (). Reset ();} / here transactionFactory uses SpringManagedTransactionFactory and if (this.transactionFactory = = null) {this.transactionFactory = new SpringManagedTransactionFactory ();} / / passes configuration.setEnvironment (new Environment (this.environment, this.transactionFactory, this.dataSource) through environment) If (! isEmpty (this.mapperLocations)) {for (Resource mapperLocation: this.mapperLocations) {if (mapperLocation = = null) {continue;} try {XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder (mapperLocation.getInputStream (), configuration, mapperLocation.toString (), configuration.getSqlFragments ()); xmlMapperBuilder.parse () } catch (Exception e) {throw new NestedIOException ("Failed to parse mapping resource:'" + mapperLocation + ", e);} finally {ErrorContext.instance (). Reset ();} if (LOGGER.isDebugEnabled ()) {LOGGER.debug (" Parsed mapper file:'"+ mapperLocation +") } else {if (LOGGER.isDebugEnabled ()) {LOGGER.debug ("Property 'mapperLocations' was not specified or no matching resources found");} return this.sqlSessionFactoryBuilder.build (configuration);}

There are a lot of methods in List-2, but all you're doing is generating Configuration.

The point we need to note is this.transactionFactory = new SpringManagedTransactionFactory (), which is the point where mybatis and spring are associated.

Looking at MapperScannerConfigurer, this class implements the BeanDefinitionRegistryPostProcessor interface, instantiates a ClassPathMapperScanner in the postProcessBeanDefinitionRegistry method, and then scan- > doScan:

List-3

Private void processBeanDefinitions (Set beanDefinitions) {GenericBeanDefinition definition; for (BeanDefinitionHolder holder: beanDefinitions) {definition = (GenericBeanDefinition) holder.getBeanDefinition (); if (logger.isDebugEnabled ()) {logger.debug ("Creating MapperFactoryBean with name'" + holder.getBeanName () + "'and'" + definition.getBeanClassName () + "'mapperInterface") } / / the mapper interface is the original class of the bean / / but, the actual class of the bean is MapperFactoryBean definition.getConstructorArgumentValues () .addGenericArgumentValue (definition.getBeanClassName ()); / / issue # 59 / / set MapperFactoryBean type definition.setBeanClass (this.mapperFactoryBean.getClass ()); definition.getPropertyValues () .add ("addToConfig", this.addToConfig); boolean explicitFactoryUsed = false If (StringUtils.hasText (this.sqlSessionFactoryBeanName)) {definition.getPropertyValues () .add ("sqlSessionFactory", new RuntimeBeanReference (this.sqlSessionFactoryBeanName)); explicitFactoryUsed = true;} else if (this.sqlSessionFactory! = null) {/ / set property reference SqlSessionFactory definition.getPropertyValues () .add ("sqlSessionFactory", this.sqlSessionFactory); explicitFactoryUsed = true } if (StringUtils.hasText (this.sqlSessionTemplateBeanName)) {if (explicitFactoryUsed) {logger.warn ("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. SqlSessionFactory is ignored. ");} definition.getPropertyValues (). Add (" sqlSessionTemplate ", new RuntimeBeanReference (this.sqlSessionTemplateBeanName)); explicitFactoryUsed = true;} else if (this.sqlSessionTemplate! = null) {if (explicitFactoryUsed) {logger.warn (" Cannot use both: sqlSessionTemplate and sqlSessionFactory together. SqlSessionFactory is ignored. ");} definition.getPropertyValues (). Add (" sqlSessionTemplate ", this.sqlSessionTemplate); explicitFactoryUsed = true;} if (! explicitFactoryUsed) {if (logger.isDebugEnabled ()) {logger.debug (" Enabling autowire by type for MapperFactoryBean with name'"+ holder.getBeanName () +". ");} definition.setAutowireMode (AbstractBeanDefinition.AUTOWIRE_BY_TYPE) }}}

The mapper interface scanned in List-3 is encapsulated as MapperFactoryBean, and SqlSessionFactory is set as its property.

The method that the MapperFactoryBean class inherits from SqlSessionDaoSupport,setSqlSessionFactory is in the parent class SqlSessionDaoSupport, as shown in List-4, and initializes the sqlSession with SqlSessionTemplate.

List-4

Public void setSqlSessionFactory (SqlSessionFactory sqlSessionFactory) {if (! this.externalSqlSession) {this.sqlSession = new SqlSessionTemplate (sqlSessionFactory);}}

Let's look at the construction method of SqlSessionTemplate, as follows: List-5

List-5

Public SqlSessionTemplate (SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {notNull (sqlSessionFactory, "Property 'sqlSessionFactory' is required"); notNull (executorType, "Property' executorType' is required"); this.sqlSessionFactory = sqlSessionFactory; this.executorType = executorType; this.exceptionTranslator = exceptionTranslator; this.sqlSessionProxy = (SqlSession) newProxyInstance (SqlSessionFactory.class.getClassLoader (), new Class [] {SqlSession.class}, new SqlSessionInterceptor ());}

SqlSessionTemplate implements the interface SqlSession,SqlSessionTemplate. All the method implementations within the interface are delegated to sqlSessionProxy. SqlSessionProxy is a dynamic proxy of JDK. Let's see SqlSessionInterceptor:

List-6

Private class SqlSessionInterceptor implements InvocationHandler {@ Override public Object invoke (Object proxy, Method method, Object [] args) throws Throwable {SqlSession sqlSession = getSqlSession (SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator); try {Object result = method.invoke (sqlSession, args) If (! isSqlSessionTransactional (sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {/ / force commit even on non-dirty sessions because some databases require / / a commit/rollback before calling close () sqlSession.commit (true);} return result;} catch (Throwable t) {Throwable unwrapped = unwrapThrowable (t) If (SqlSessionTemplate.this.exceptionTranslator! = null & & unwrapped instanceof PersistenceException) {/ / release the connection to avoid a deadlock if the translator is no loaded. See issue # 22 closeSqlSession (sqlSession, SqlSessionTemplate.this.sqlSessionFactory); sqlSession = null; Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible ((PersistenceException) unwrapped); if (translated! = null) {unwrapped = translated;}} throw unwrapped;} finally {if (sqlSession! = null) {closeSqlSession (sqlSession, SqlSessionTemplate.this.sqlSessionFactory) }

In List-6, you first get the SqlSession, and if the SqlSession does not exist, create one through sessionFactory.openSession.

List-7

Public static SqlSession getSqlSession (SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {notNull (sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED); notNull (executorType, NO_EXECUTOR_TYPE_SPECIFIED); SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource (sessionFactory); SqlSession session = sessionHolder (executorType, holder); if (session! = null) {return session;} if (LOGGER.isDebugEnabled ()) {LOGGER.debug ("Creating a new SqlSession") } session = sessionFactory.openSession (executorType); registerSessionHolder (sessionFactory, executorType, exceptionTranslator, session); return session;}

SessionFactory.openSession ()-> openSessionFromDataSource (), gets the Environemnt, then gets the SpringManagedTransactionFactory in the TransactionFactory--List-2 from Environment, and newTransaction () returns the SpringManagedTransaction.

List-8

Private SqlSession openSessionFromDataSource (ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = null; try {final Environment environment = configuration.getEnvironment (); final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment (environment); tx = transactionFactory.newTransaction (environment.getDataSource (), level, autoCommit); final Executor executor = configuration.newExecutor (tx, execType); return new DefaultSqlSession (configuration, executor, autoCommit);} catch (Exception e) {closeTransaction (tx) / / may have fetched a connection so lets call close () throw ExceptionFactory.wrapException ("Error opening session. Cause: "+ e, e);} finally {ErrorContext.instance () .reset ();}}

Final Executor executor = configuration.newExecutor (tx, execType), default is SimpleExecutor, now that SqlSession has it, go back to the method.invoke () of List-6, that is, this method will be called when it is actually called. Take update as an example, see the doUpdate method of SimpleExecutor

List-9

Override public int doUpdate (MappedStatement ms, Object parameter) throws SQLException {Statement stmt = null; try {Configuration configuration = ms.getConfiguration (); StatementHandler handler = configuration.newStatementHandler (this, ms, parameter, RowBounds.DEFAULT, null, null); stmt = prepareStatement (handler, ms.getStatementLog ()); return handler.update (stmt);} finally {closeStatement (stmt);}}

Let's take a look at prepareStatement (), as shown in List-10, which uses transaction.getConnection to get Connection, and this transaction is SpringManagedTransaction.

List-10

Private Statement prepareStatement (StatementHandler handler, Log statementLog) throws SQLException {Statement stmt; Connection connection = getConnection (statementLog); stmt = handler.prepare (connection, transaction.getTimeout ()); handler.parameterize (stmt); return stmt;} protected Connection getConnection (Log statementLog) throws SQLException {Connection connection = transaction.getConnection (); if (statementLog.isDebugEnabled ()) {return ConnectionLogger.newInstance (connection, statementLog, queryStack);} else {return connection;}}

GetConnection in SpringManagedTransaction will call openConnection, as shown in List-11

List-11

Private void openConnection () throws SQLException {this.connection = DataSourceUtils.getConnection (this.dataSource); this.autoCommit = this.connection.getAutoCommit (); this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional (this.connection, this.dataSource) If (LOGGER.isDebugEnabled ()) {LOGGER.debug ("JDBC Connection [" + this.connection + "] will" + (this.isConnectionTransactional? "": "not") + "be managed by Spring");}}

Get Connection- > doGetConnection () through DataSourceUtils.getConnection (), get ConnectionHler from TransactionSynchronizationManager, and get a Connection; through dataSource if it is null. If it is not null and the thing has been opened, return the connection in connectionHolder directly.

List-12

Public static Connection doGetConnection (DataSource dataSource) throws SQLException {Assert.notNull (dataSource, "No DataSource specified"); ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource (dataSource); if (conHolder = = null | |! conHolder.hasConnection () & &! conHolder.isSynchronizedWithTransaction ()) {logger.debug ("Fetching JDBC Connection from DataSource"); Connection con = dataSource.getConnection () If (TransactionSynchronizationManager.isSynchronizationActive ()) {logger.debug ("Registering transaction synchronization for JDBC Connection"); ConnectionHolder holderToUse = conHolder; if (conHolder = = null) {holderToUse = new ConnectionHolder (con);} else {conHolder.setConnection (con);} holderToUse.requested () TransactionSynchronizationManager.registerSynchronization (new DataSourceUtils.ConnectionSynchronization (holderToUse, dataSource)); holderToUse.setSynchronizedWithTransaction (true); if (holderToUse! = conHolder) {TransactionSynchronizationManager.bindResource (dataSource, holderToUse);}} return con;} else {conHolder.requested () If (! conHolder.hasConnection ()) {logger.debug ("Fetching resumed JDBC Connection from DataSource"); conHolder.setConnection (dataSource.getConnection ());} return conHolder.getConnection ();}}

TransactionSynchronizationManager holds the ConnectionHolder through ThreadLocal, and ConnectionHolder is held through this class in Spring tx.

The above is all the content of the article "sample Analysis of Mybatis Spring and Mybatis things transaction". Thank you for reading! Hope to share the content to help you, more related knowledge, welcome to follow the industry information channel!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report