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

How to use Mybatis and analyze the principle of Integration with Spring

2025-02-25 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

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

How to use Mybatis and integrate with Spring principle analysis, I believe that many inexperienced people do not know what to do, so this paper summarizes the causes of the problem and solutions, through this article I hope you can solve this problem.

Preface

The main points of the topic are as follows:

What needs to be solved here is the second point, the use and principle of Mybatis and the analysis of the principle of integration with Spring.

Simple use of Mybatis to build the project pom file to add the following dependencies

Org.mybatis

Mybatis

3.4.6

Mysql

Mysql-connector-java

8.0.15

Create a mybaits profile, mybatis-config.xml

Create the mapper.xml file as follows

Select * from user where id = # {id}

Entity classes are as follows: public class User {

Private int id

Private String name

Private int age

/ / omit the getter/setter method

@ Override

Public String toString () {

Return "User {" +

"id=" + id +

", name='" + name +'\'+

", age=" + age +

'}'

}

}

The test code is as follows: public class Main {

Public static void main (String [] args) throws Exception {

String resource = "mybatis-config.xml"

InputStream resourceAsStream = Resources.getResourceAsStream (resource)

/ / 1. Parsing XML configuration

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder ()

/ / 2. Create a SqlSessionFactory based on the parsed XML configuration

SqlSessionFactory sqlSessionFactory = builder.build (resourceAsStream)

/ / 3. Create a SqlSession through SqlSessionFactory

SqlSession sqlSession = sqlSessionFactory.openSession ()

/ / 4. The test calls the method in mapper.xml directly

Object o = sqlSession.selectOne ("org.apache.ibatis.dmz.mapper.UserMapper.selectOne", 2)

If (o instanceof User) {

System.out.println ("directly execute the sql query results in the mapper file:" + o)

}

/ / 5. Get a proxy object

UserMapper mapper = sqlSession.getMapper (UserMapper.class)

/ / 6. Call the method of the proxy object

System.out.println ("proxy object query results:" + mapper.selectOne (1))

}

}

/ / the program output is as follows, corresponding to two records in my local database

/ / execute the sql query result in the mapper file directly: User {id=2, name='dmz', age=18}

/ / query result of proxy object: User {id=1, name='dmz', age=18}

Principle analysis

Because this column is not a source code analysis topic for mybatis (the author will do a source code analysis topic for all three frameworks), the principle analysis of this piece will not involve too much source code level content.

As we can see from the above example, there are two main forms of using Mybatis

Call the relevant addition, deletion, modification and query API directly through sqlsession. For example, in our above example, we directly call the selectOne method of sqlsession to complete the query. Using this method, we need to pass in namespace+statamentId so that Mybatis can locate the SQL to be executed. In addition, we need to pass in the parameters of the query. In the second form, we first create a proxy object through sqlsession, and then call the method of the proxy object to complete the query.

The principle to be explored in this article is mainly the use of the second form, in other words, how Mybatis generates this proxy object. Before we think about how Mybatis does it, let's think about how you would do it if we were to do it ourselves.

If it were me, I would do this:

Of course, I left out a lot of details, such as how to bind method parameters to SQL, how to encapsulate the result set, whether to cache the same Sql, and so on. A normal Mybatis needs to go through at least the following processes when executing Sql

nine

Among them, Executor is responsible for maintaining cache and transaction management, it will delegate the related operations to StatementHandler, StatementHandler will first bind the parameters of Sql statement through ParameterHandler, then call JDBC-related API to execute Sql to get the result set, and finally complete the encapsulation of the result set through ResultHandler.

This article only needs to have a general understanding of the process. We will talk about it in Mybatis's source code analysis column for a detailed introduction of the process.

Transaction Management in Mybaits

There are two main ways of transaction management in Mybatis.

Using the transaction management mechanism of JDBC: that is, using the java.sql.Connection object in JDBC to complete the transaction commit (commit ()), rollback (rollback ()), shutdown (close ()), etc.

Use MANAGED's transaction management mechanism: this mechanism MyBatis itself does not implement transaction management, but allows the program's container, such as (tomcat,jboss), to manage transactions.

In the example at the beginning of the article, I configured the

This means that we have chosen the transaction management mechanism of JDBC, so where can we start the transaction? In fact, Mybatis defaults to turning off autocommit, which means that transactions are on by default. We can control whether to start the transaction or not when we create the SqlSession. SqlSessionFactory provides the following methods for creating SqlSession

SqlSession openSession ()

SqlSession openSession (boolean autoCommit)

SqlSession openSession (Connection connection)

SqlSession openSession (TransactionIsolationLevel level)

SqlSession openSession (ExecutorType execType, TransactionIsolationLevel level)

SqlSession openSession (ExecutorType execType)

SqlSession openSession (ExecutorType execType, boolean autoCommit)

SqlSession openSession (ExecutorType execType, Connection connection)

We think which method to use to create SqlSession is mainly based on the following points

Whether to turn off autocommit means to enable transactions to use externally incoming connection objects or connection objects obtained from configuration information. There are three ways to execute ExecutorType.SIMPLE: create a new PreparedStatementExecutorType.REUSE every time you execute SQL: reuse PreparedStatement objects ExecutorType.BATCH: batch

In the previous example, we used the null parameter method to create the SqlSession object, in which case Mybatis creates a SqlSession object with transaction enabled, connection obtained from the configured connection pool, transaction isolation level consistent with the database, and executed in ExecutorType.SIMPLE.

Let's take a look at transaction management in Mybatis based on the above example. The code is as follows:

Public class Main {

Public static void main (String [] args) throws Exception {

String resource = "mybatis-config.xml"

InputStream resourceAsStream = Resources.getResourceAsStream (resource)

/ / 1. Parsing XML configuration

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder ()

/ / 2. Create a SqlSessionFactory based on the parsed XML configuration

SqlSessionFactory sqlSessionFactory = builder.build (resourceAsStream)

/ / 3. Open a SqlSession

SqlSession sqlSession = sqlSessionFactory.openSession ()

/ / 4. Get a proxy object

UserMapper mapper = sqlSession.getMapper (UserMapper.class)

User user = new User ()

User.setId (3)

User.setName ("dmz111")

User.setAge (27)

/ / insert a piece of data

Mapper.insert (user)

/ / throw an exception

Throw new RuntimeException ("exception!")

}

}

By running the above code, we will find that there is no new data in the database, but if we use the following method when creating the SqlSession

SqlSession sqlSession = sqlSessionFactory.openSession (true)

Even if an exception occurs, the data will still be inserted into the database

The principle of Spring integrating Mybatis

First of all, although I introduced Mybatis's transaction management earlier, when Mybatis is integrated with Spring, transaction management is completely controlled by Spring! Therefore, the analysis of the principle of integration will not involve transaction management.

Let's first take a look at a case where Spring integrates Mybatis. Here, I integrate it in the form of JavaConfig. The core configuration is as follows:

@ Configuration

@ ComponentScan ("com.dmz.mybatis.spring")

/ / scan all mapper interfaces

@ MapperScan ("com.dmz.mybatis.spring.mapper")

Public class MybatisConfig {

@ Bean

Public DataSource dataSource () {

DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource ()

DriverManagerDataSource.setPassword ("123")

DriverManagerDataSource.setUsername ("root")

DriverManagerDataSource.setDriverClassName ("com.mysql.jdbc.Driver")

DriverManagerDataSource.setUrl ("jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8")

Return driverManagerDataSource

}

/ / you need to configure this SqlSessionFactoryBean to get a SqlSessionFactory

@ Bean

Public SqlSessionFactoryBean sqlSessionFactoryBean () throws Exception {

SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean ()

SqlSessionFactoryBean.setDataSource (dataSource ())

PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver ()

SqlSessionFactoryBean.setMapperLocations (patternResolver.getResources ("classpath:mapper/*.xml"))

Return sqlSessionFactoryBean

}

/ / use DataSourceTransactionManager in Spring to manage transactions

@ Bean

Public TransactionManager transactionManager () {

DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager ()

DataSourceTransactionManager.setDataSource (dataSource ())

Return dataSourceTransactionManager

}

}

From this configuration, we can extract a key message. If we want to figure out how Spring integrates Mybatis, we should understand two points.

What does the @ MapperScan annotation do? What did SqlSessionFactoryBean do in the process of creating the Bean?

Next, we will discuss it in two ways.

Initialization process of SqlSessionFactoryBean

First of all, let's look at the inheritance relationship of this class.

Inheritance relationship

Source code analysis

When we see that it implements the InitializingBean interface, our first reaction must be to take a look at its afterPropertiesSet method, whose source code is as follows:

Public void afterPropertiesSet () throws Exception {

/ / call the buildSqlSessionFactory method to complete the assignment of the member attribute sqlSessionFactory

This.sqlSessionFactory = buildSqlSessionFactory ()

}

/ / build a SqlSessionFactory with the information we specified in the configuration

/ / if you have any knowledge of the source code of mybatis

/ / what this method does is actually construct a Configuration object first.

/ / this Configuration object represents all the configuration information

/ / equivalent to the configuration information we specified through myabtis-config.xml

/ / then call the build method of sqlSessionFactoryBuilder to create a SqlSessionFactory

Protected SqlSessionFactory buildSqlSessionFactory () throws Exception {

Final Configuration targetConfiguration

/ / next is the process of building Configuration objects from configuration information

/ / I only keep a few important node information here.

XMLConfigBuilder xmlConfigBuilder = null

/ / We can specify the location of the mybatis-config.xml directly through configLocation

If (this.configuration! = null) {

TargetConfiguration = this.configuration

If (targetConfiguration.getVariables ()) = = null) {

TargetConfiguration.setVariables (this.configurationProperties)

} else if (this.configurationProperties! = null) {

TargetConfiguration.getVariables () putAll (this.configurationProperties)

}

} else if (this.configLocation! = null) {

XmlConfigBuilder = new XMLConfigBuilder (this.configLocation.getInputStream (), null, this.configurationProperties)

TargetConfiguration = xmlConfigBuilder.getConfiguration ()

} else {

LOGGER.debug (

()-> "Property 'configuration' or' configLocation' not specified, using default MyBatis Configuration")

TargetConfiguration = new Configuration ()

Optional.ofNullable (this.configurationProperties) .ifPresent (targetConfiguration::setVariables)

}

/ / aliases can be specified

If (hasLength (this.typeAliasesPackage)) {

ScanClasses (this.typeAliasesPackage, this.typeAliasesSuperType). Stream ()

.filter (clazz->! clazz.isAnonymousClass ()) .filter (clazz->! clazz.isInterface ())

.filter (clazz->! clazz.isMemberClass ()) .forEach (targetConfiguration.getTypeAliasRegistry ():: registerAlias)

}

If (! isEmpty (this.typeAliases)) {

Stream.of (this.typeAliases) .forEach (typeAlias-> {

TargetConfiguration.getTypeAliasRegistry () registerAlias (typeAlias)

LOGGER.debug (()-> "Registered type alias:'" + typeAlias + "'")

});

}

/ / it is important here. Note that the transaction is managed by Spring here.

TargetConfiguration.setEnvironment (new Environment (this.environment)

This.transactionFactory = = null? New SpringManagedTransactionFactory (): this.transactionFactory

This.dataSource))

/ / you can specify mapper.xml directly

If (this.mapperLocations! = null) {

If (this.mapperLocations.length = = 0) {

LOGGER.warn (()-> "Property 'mapperLocations' was specified but matching resources are not found.")

} else {

For (Resource mapperLocation: this.mapperLocations) {

If (mapperLocation = = null) {

Continue

}

Try {

XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder (mapperLocation.getInputStream ()

TargetConfiguration, mapperLocation.toString (), targetConfiguration.getSqlFragments ()

XmlMapperBuilder.parse ()

} catch (Exception e) {

Throw new NestedIOException ("Failed to parse mapping resource:'" + mapperLocation + "", e)

} finally {

ErrorContext.instance () .reset ()

}

LOGGER.debug (()-> "Parsed mapper file:'" + mapperLocation + "'")

}

}

} else {

LOGGER.debug (()-> "Property 'mapperLocations' was not specified.")

}

Return this.sqlSessionFactoryBuilder.build (targetConfiguration)

}

You can see that the most important thing to do in the initialization phase is to assign a value to the member variable sqlSessionFactory, and we know that this is a FactoryBean, so it is not unexpected that its getObject can return the assigned member variable, and its source code is as follows:

Public SqlSessionFactory getObject () throws Exception {

/ / the initialization phase has been assigned

If (this.sqlSessionFactory = = null) {

AfterPropertiesSet ()

}

/ / sure enough, go straight back.

Return this.sqlSessionFactory

}

@ MapperScan how it works

Looking at the source code of the @ MapperScan annotation, we will find that

@ Retention (RetentionPolicy.RUNTIME)

@ Target (ElementType.TYPE)

@ Documented

@ Import (MapperScannerRegistrar.class)

@ Repeatable (MapperScans.class)

Public @ interface MapperScan {

Alias of / / basePackages attribute, equivalent to basePackages

String [] value () default {}

/ / name of the scanned package

String [] basePackages () default {}

/ / you can provide a class with the package name of the class as the scanned package

Class [] basePackageClasses () default {}

/ / the generator of BeanName is generally fine with the default one

Class markerInterface () default Class.class

/ / specify the name of the SqlSessionTemplate

/ / SqlSessionTemplate is the encapsulation of SqlSession in Mybatis by Spring

String sqlSessionTemplateRef () default ""

/ / specify the name of the SqlSessionFactory

String sqlSessionFactoryRef () default ""

/ / what does this attribute mean? Integration of Spring and Mybatis

/ / the most important thing is to leave the proxy object generated by Mybatis to Spring to manage

/ / it is this MapperFactoryBean that implements this function.

Class

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