In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
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.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.