primary coverage
1. Getting started
-
Preparing the database
-
Our needs
-
Using idea to create a project
-
Introducing mybatis dependency in pom.xml
-
Configure mybatis global profile
-
Create Mapper xml file
-
Mapper xml file in mybatis global configuration file
-
Building SqlSessionFactory objects
-
Building SqlSession object
-
Introduce lombok (not required)
-
Introduce logback support (not required)
-
Write a test case
2. Using sqlsession to perform sql operations
-
Common usage of SqlSession
-
New operation
-
Execution deletion
-
Execution modification
-
Execution query
3. Use of Mapper interface
-
Why Mapper interface is needed
-
Mapper interface usage
-
Case: use Mapper interface to add, delete, modify and query
-
Some points for attention when using Mapper interface
-
The principle of Mapper interface
4. How to obtain case source code
quick get start
Preparing the database
Execute the following sql in mysql:
/*Create database javacode2018*/ DROP DATABASE IF EXISTS `javacode2018`; CREATE DATABASE `javacode2018`; USE `javacode2018`; /*Create table structure*/ DROP TABLE IF EXISTS `t_user`; CREATE TABLE t_user ( id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT 'Primary key, user id,Automatic growth', `name` VARCHAR(32) NOT NULL DEFAULT '' COMMENT 'Full name', `age` SMALLINT NOT NULL DEFAULT 1 COMMENT 'Age', `salary` DECIMAL(12,2) NOT NULL DEFAULT 0 COMMENT 'salary', `sex` TINYINT NOT NULL DEFAULT 0 COMMENT 'Gender,0:Unknown,1:male,2:female' ) COMMENT 'User table'; SELECT * FROM t_user;
Above we created a database: javacode2018, a user table t ﹣ user.
Our needs
Use mybatis to add, delete, modify and query the t ﹣ user table.
Using idea to create a project
In the previous article, we created another module chat02 in the mybatis series project. The process is as follows:
Select mybatis series, as shown below:
Right click - > New - > module, as shown below:
Select Maven in the above figure and click Next, as shown below:
The following window appears:
In the above figure, enter ArtifactId as chat02, and click Next, as shown below:
Click Finish in the figure above to complete the creation of chat02 module. The project structure is as follows:
Introducing mybatis dependency in pom.xml
<dependencies> <!-- mybatis rely on --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> </dependency> <!-- mysql drive --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- lombok Support --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- unit testing junit Support --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <!-- Introduce logback Used to output logs --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </dependency> </dependencies>
In the above, we have introduced the support of relying on mybatis, mysql driver, lombok, junit and logback. In fact, to run mybatis, we only need to introduce the following component:
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> </dependency>
Note: the version number is not written in the construction introduced by POM above, because the version number of the component has been declared in the parent pom.xml, so there is no need to write in chat03/pom.xml.
Configure mybatis global profile
If you use mybatis to operate the database, you need to configure the database related information, which needs to be configured in the mybatis global configuration file.
Mybatis needs to provide a global configuration xml file. You can configure mybatis in this configuration file, such as transaction support, data source configuration, etc. This belongs to the configuration file, which we usually put in main/resource.
Create the mybatis-config.xml file in chat03/src/main/resource, as follows:
<?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> <!-- Environment configuration, you can configure multiple environments --> <environments default="chat03"> <!-- environment Used to configure an environment id: Environment identification, unique --> <environment id="chat03"> <!-- Transaction manager factory configuration --> <transactionManager type="org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory"/> <!-- Data source factory configuration, using factories to create data sources --> <dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/javacode2018?characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="root123"/> </dataSource> </environment> </environments> </configuration>
Let's explain.
configuration element
This is the root element of mybatis global configuration file. Each configuration file has only one
environments element
What is the environment information used to configure mybatis? For example, development environment, test environment and online environment, the databases in these three environments may be different, and there may be more environments.
The environment element is used to configure multiple environments. A specific environment is configured with the environment element. The environment element has an id to identify a specific environment.
With so many environments configured, which one will mybatis use?
The environments element has a default attribute that specifies which environment to use by default, such as chat03.
environment element
It is used to configure specific environment information. This element has two sub elements: transactionManager and dataSource
-
transactionManager element
To configure a transaction factory, there is a type attribute. The value of the type must be the implementation class of the org.apache.ibatis.transaction.TransactionFactory interface. The TransactionFactory can be seen as a factory by its name. To create a transaction manager org.apache.ibatis.transaction.Transaction object, the TransactionFactory interface has two implementations by default:
org.apache.ibatis.transaction.managed.ManagedTransactionFactory org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory
In general, we use org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory, which integrates mybatis with other frameworks, such as integrating with spring. Transactions are controlled by spring. In spring, there is an implementation of TransactionFactory interface, org.mybatis.spring.transaction.SpringManagedTransactionFactory. Interested friends can go and study it. When that time comes I'll talk about the use of spring later.
-
dataSource element
For data source configuration, the value of type attribute must be the implementation class of interface org.apache.ibatis.datasource.DataSourceFactory. DataSourceFactory is also a factory, which is used to create data source javax.sql.DataSource object. This interface in mybatis has three implementation classes by default:
org.apache.ibatis.datasource.jndi.JndiDataSourceFactory org.apache.ibatis.datasource.pooled.PooledDataSourceFactory org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory
We use the second org.apache.ibatis.datasource.pooled.pooledatasourcefactory, which is used to create a database connection pool type data source. It can realize database connection sharing and reduce the time of repeated connection creation and destruction.
To configure the data source, you need to specify the property information of the database connection, such as the url, user name, and password of the driver and connection db. This is configured in the property under the data source element, and the format of the property element:
<property name="Attribute name" value="value"/>
Create Mapper xml file
We need to operate on the t Uuser table. We need to write sql. Where is the sql written?
In mybatis, we usually write all sql operations of a table in a mapper xml, which is generally named XXXMapper.xml format.
Create the file chat02/src/main/resource/mapper/UserMapper.xml, as follows:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.javacode2018.chat02.UserMapper"> </mapper>
The root element of mapper XML is mapper. This element has a namespace attribute. There will be many tables in the system. Each table corresponds to a mapper XML. In order to prevent the duplication of mapper files, we need to specify a namespace for each mapper XML file. Through this, we can distinguish each mapper XML file. Above we specify com.javacode2018.chat02.UserMapper.
In a moment, we will write the sql related to all operations of the t Uuser table in the above xml.
Mapper xml file in mybatis global configuration file
We have written UserMapper.xml. How can we let mybatis know this file? At this time, we need to introduce UserMapper.xml into mybatis-config.xml global configuration file, and add the following configuration into mybatis-config.xml:
<mappers> <mapper resource="mapper/UserMapper.xml" /> </mappers>
There are multiple mapper elements under the mappers element. Mapper xml file can be imported through the resource attribute of mapper element, and resource is the path relative to classes.
All the configuration files mentioned above are ok. Now we need to run mybatis. At this time, we need to use some java objects in mybatis.
Building SqlSessionFactory objects
//Specify mybatis global profile String resource = "mybatis-config.xml"; //Read global profile InputStream inputStream = Resources.getResourceAsStream(resource); //Building SqlSessionFactory objects SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactory is an interface and a heavyweight object. SqlSessionFactoryBuilder creates a SqlSessionFactory by reading the global configuration file. It takes a lot of time to create this object, mainly in parsing the global configuration file of mybatis. The global configuration file contains many contents. SqlSessionFactoryBuilder parses these contents, A complex SqlSessionFactory object is created. The life cycle of this object is generally the same as that of the application. It is created as the application starts and ends as the application stops. Therefore, it is generally a global object. Generally, a db corresponds to a SqlSessionFactory object.
Building SqlSession object
SqlSession is equivalent to Connection object in jdbc and a Connection of database. You can use SqlSession to operate on db, such as executing sql, committing transaction, closing Connection, etc. you need to create SqlSession object through SqlSessionFactory. There are two methods commonly used in SqlSessionFactory to create SqlSession object, as follows:
//Create a SqlSession, the transaction will not be automatically committed by default SqlSession openSession(); //Create a SqlSession,autoCommit: specify whether to automatically commit the transaction SqlSession openSession(boolean autoCommit);
There are many methods in SqlSession interface, which are directly used to operate db. The list of methods is as follows, familiar to you:
<T> T selectOne(String statement); <T> T selectOne(String statement, Object parameter); <E> List<E> selectList(String statement); <E> List<E> selectList(String statement, Object parameter); <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds); <K, V> Map<K, V> selectMap(String statement, String mapKey); <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey); <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds); <T> Cursor<T> selectCursor(String statement); <T> Cursor<T> selectCursor(String statement, Object parameter); <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds); void select(String statement, Object parameter, ResultHandler handler); void select(String statement, ResultHandler handler); void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler); int insert(String statement); int insert(String statement, Object parameter); int update(String statement); int update(String statement, Object parameter); int delete(String statement); int delete(String statement, Object parameter); void commit(); void commit(boolean force); void rollback(); void rollback(boolean force); List<BatchResult> flushStatements(); void close(); void clearCache(); Configuration getConfiguration(); <T> T getMapper(Class<T> type); Connection getConnection();
The above start with select can query the db, insert can insert the db, and update can update the db.
Introduce lombok support (not required)
Just to be clear: lombok is not necessary for mybatis. It is used to simplify the code. We will often use it later.
Lombok can simplify java code in the form of simple annotations and improve the development efficiency of developers. For example, Java beans that often need to be written in development need to take time to add corresponding getters / setters, maybe to write constructor, equals and other methods, and need to be maintained. When there are many properties, there will be a large number of getter/setter methods, which are very lengthy and not too technical. Once the properties are modified, it is easy to forget to modify the corresponding methods.
Lombok can automatically generate constructor, getter/setter, equals, hashcode and toString methods for properties during compilation through annotation. The magic is that there are no getter and setter methods in the source code, but there are getter and setter methods in the bytecode file generated by compilation. This saves the trouble of manually rebuilding the code and makes the code look more concise.
How to use lombok
-
Install lombok plug-in in idea first
Open idea, click file - > Settings - > plugins, search Lombok Plugin, and click Install.
-
lombok support in maven
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.10</version> <scope>provided</scope> </dependency>
-
Use lombok related functions in the code
Introduce logback (not required)
Just to be clear: mybatis is is not a necessary log framework, and it can run normally without configuration.
In order to view the logs generated during the operation of mybatis, such as the executed sql, sql parameters, sql execution results and other debugging information, we need to introduce the support of the log framework. logback is a good log framework. Here we use this
Steps of integrating logback in mybatis
-
logback support in maven
<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency>
-
Create logback.xml file in src/main/resources:
<?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <logger name="com.javacode2018" level="debug" additivity="false"> <appender-ref ref="STDOUT" /> </logger> </configuration>
The specific writing method of logback.xml is not the scope of this article. Interested friends can study the specific usage of logback.
All classes in package com.javacode2018 are configured in the above xml. When logback is used to output logs, the logs of debug level and above will be output to the console for our convenience.
Write a test case
Create a class under chat02/src/test:
com.javacode2018.chat02.UserTest
The contents are as follows:
package com.javacode2018.chat02; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.io.InputStream; @Slf4j public class UserTest { private SqlSessionFactory sqlSessionFactory; @Before public void before() throws IOException { //Specify mybatis global profile String resource = "mybatis-config.xml"; //Read global profile InputStream inputStream = Resources.getResourceAsStream(resource); //Building SqlSessionFactory objects SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); this.sqlSessionFactory = sqlSessionFactory; } @Test public void sqlSession() { SqlSession sqlSession = this.sqlSessionFactory.openSession(); log.info("{}", sqlSession); } }
There is a @ Slf4j annotation in the above code, which is provided by lombok. You can generate the following code in this class:
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(UserTest.class);
Run the above use case: sqlSession method. The output is as follows:
45:51.289 [main] INFO com.javacode2018.chat02.UserTest - org.apache.ibatis.session.defaults.DefaultSqlSession@1f021e6c
Using sqlsession to perform sql operations
Common usage of SqlSession
SqlSession is equivalent to a connection. You can use this object to add, delete, modify and query the db. After the operation, you need to close it. Steps:
1. Get SqlSession object: get SqlSession object through the sqlSessionFactory.openSession method 2. Operate on db: use SqlSession object to operate on db 3. Close SqlSession object: sqlSession.close();
The common usage is as follows:
//Get SqlSession SqlSession sqlSession = this.sqlSessionFactory.openSession(); try { //Perform business operations, such as adding, deleting, modifying and querying } finally { //Close SqlSession sqlSession.close(); }
Above, we put the closing of SqlSession in the finally block and make sure that close() will execute. The simpler way is to use try() in java, as follows:
try (SqlSession sqlSession = this.sqlSessionFactory.openSession();) { //Perform business operations, such as adding, deleting, modifying and querying }
New operation
Requirement: pass in the UserModel object, and then insert the data of this object into the t Uuser table.
Create a ` UserModel`
Create a new com.javacode2018.chat02.UserModel class. The code is as follows:
package com.javacode2018.chat02; import lombok.*; /** * The official account: Java, a former passerby, worked for 10 years before Ali P7 shared Java, algorithm and database technology dry cargo. Strong credit technology changes the fate, let the family live a more decent life! */ @Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder @ToString public class UserModel { private Long id; private String name; private Integer age; private Double salary; private Integer sex; }
The fields of this class correspond to the t Uuser table.
Insert operation defined in UserMapper.xml
We have said that for all sql operations of the t_user table, we put them in UserMapper.xml. We add the following configuration in UserMapper.xml, and use the insert element to define the insert operation:
<!-- insert Used to define an insert operation id: Specific identification of operation parameterType: Specifies the type of parameter accepted by the insert operation --> <insert id="insertUser" parameterType="com.javacode2018.chat02.UserModel"> <![CDATA[ INSERT INTO t_user (id,name,age,salary,sex) VALUES (#{id},#{name},#{age},#{salary},#{sex}) ]]> </insert>
The insert element is used to define an insert operation on db
id: it is an identifier of the operation. When the operation is performed through mybatis, it will be referenced to the insert operation through the namespace and id,
parameterType: used to specify the type of parameters accepted by the insert operation. It can be a variety of java objects of javabean, map, list and collection types. We accept the UserModel object for this insert.
The specific sql is defined inside the insert element. As you can see, it is an insert sql, which inserts data into the t Uuser table.
The value to be inserted is obtained from the UserModel object, and the field of the UserModel object is taken. The value of the field in the UserModel can be obtained by using {field} format.
Call SqlSession.insert method to perform the insert operation
We have written the sql inserted by t_user in UserMapper. How can we call it at this time?
SqlSession.insert method needs to be called:
int insert(String statement, Object parameter)
This method has two parameters:
statement: indicates the operation. The value is the namespace of Mapper xml. The id of the specific operation. If you need to call the insertUser operation in UserMapper.xml, the value is:
com.javacode2018.chat02.UserMapper.insertUser
Parameter: the parameter of the insert operation is the same as the type specified by the parameterType in the insert in Mapper xml.
The return value is the number of rows inserted.
A new test case is added to the UserTest class:
@Test public void insertUser() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(false);) { //Create UserModel object UserModel userModel = UserModel.builder().id(2L).name("javacode2018").age(30).salary(50000D).sex(1).build(); //Perform insert operation int result = sqlSession.insert("com.javacode2018.chat02.UserMapper.insertUser", userModel); log.info("Insert number of affected rows:{}", result); //Submission of affairs sqlSession.commit(); } }
The operation output is as follows:
01:46.683 [main] DEBUG c.j.chat02.UserMapper.insertUser - ==> Preparing: INSERT INTO t_user (id,name,age,salary,sex) VALUES (?,?,?,?,?) 01:46.745 [main] DEBUG c.j.chat02.UserMapper.insertUser - ==> Parameters: 2(Long), javacode2018(String), 30(Integer), 50000.0(Double), 1(Integer) 01:46.751 [main] DEBUG c.j.chat02.UserMapper.insertUser - <== Updates: 1 01:46.751 [main] INFO com.javacode2018.chat02.UserTest - Number of affected lines: 1
Detailed sql statements and sql parameter information are printed in the output. You can see that {} in Mapper xml is replaced by?, which uses PreparedStatement in jdbc to set the parameter value.
The second line in the output details the value of the parameter and the type of each value.
The third line outputs the result of insert as 1, indicating that the insert succeeded in 1 record.
Go to db and check it out. The insertion is successful as follows:
mysql> SELECT * FROM t_user; +----+---------------+-----+----------+-----+ | id | name | age | salary | sex | +----+---------------+-----+----------+-----+ | 1 | Passerby a Java | 30 | 50000.00 | 1 | +----+---------------+-----+----------+-----+ 1 row in set (0.00 sec)
In the above code, SqlSession is created by sqlSessionFactory.openSession(). This method creates SqlSession. Internal transactions are not submitted automatically, so we need to submit them manually:
sqlSession.commit();
If you want to commit the transaction automatically, you can change the above test case to the following:
@Test public void insertUser() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) { //Create UserModel object UserModel userModel = UserModel.builder().id(1L).name("Passerby a Java").age(30).salary(50000D).sex(1).build(); //Perform insert operation int result = sqlSession.insert("com.javacode2018.chat02.UserMapper.insertUser", userModel); log.info("Number of affected lines:{}", result); } }
The above call sqlSessionFactory.openSession(true) when creating SqlSession specifies that the transaction is in auto commit mode, so we don't need to commit the transaction manually in the end.
update operation
Requirement: pass in the UserModel object and update the data with the id.
Update operation defined in UserMapper.xml
Use update to define the update operation:
<!-- update Used to define an update operation id: Specific identification of operation parameterType: Specifies the type of parameter the operation accepts --> <update id="updateUser" parameterType="com.javacode2018.chat02.UserModel"> <![CDATA[ UPDATE t_user SET name = #{name},age = #{age},salary = #{salary},sex = #{sex} WHERE id = #{id} ]]> </update>
The writing method is similar to that of insert operation. Specify id ID id and parameterType to specify parameter type of operation. The element body is the specific sql statement.
Call SqlSession.update method to perform update operation
SqlSession.update method needs to be called:
int update(String statement, Object parameter)
This method has two parameters:
statement: indicates which operation. The value is the namespace of Mapper xml. The id of the specific operation. If you need to call the updateUser operation in UserMapper.xml, the value is:
com.javacode2018.chat02.UserMapper.updateUser
Parameter: the parameter of update operation is consistent with the type specified by parameterType in update in Mapper xml.
The return value is the number of rows affected by update.
A new test case is added to the UserTest class:
@Test public void updateUser() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) { //Create UserModel object UserModel userModel = UserModel.builder().id(1L).name("Passerby a Java,Hello").age(18).salary(5000D).sex(0).build(); //Perform update operation int result = sqlSession.update("com.javacode2018.chat02.UserMapper.updateUser", userModel); log.info("Number of affected lines:{}", result); } }
Operation output:
14:09.051 [main] DEBUG c.j.chat02.UserMapper.updateUser - ==> Preparing: UPDATE t_user SET name = ?,age = ?,salary = ?,sex = ? WHERE id = ? 14:09.095 [main] DEBUG c.j.chat02.UserMapper.updateUser - ==> Parameters: Passerby a Java,Hello(String), 18(Integer), 5000.0(Double), 0(Integer), 1(Long) 14:09.100 [main] DEBUG c.j.chat02.UserMapper.updateUser - <== Updates: 1 14:09.101 [main] INFO com.javacode2018.chat02.UserTest - Number of affected lines: 1
db to see:
mysql> SELECT * FROM t_user; +----+------------------------+-----+----------+-----+ | id | name | age | salary | sex | +----+------------------------+-----+----------+-----+ | 1 | Passerby a Java,Hello | 18 | 5000.00 | 0 | | 2 | javacode2018 | 30 | 50000.00 | 1 | +----+------------------------+-----+----------+-----+ 2 rows in set (0.00 sec)
Delete operation
Requirement: delete the corresponding user record according to the user id
Delete operation defined in UserMapper.xml
Use the update element to define the delete operation:
<!-- update Used to define a delete operation id: Specific identification of operation parameterType: Specifies the type of parameter the operation accepts --> <update id="deleteUser" parameterType="java.lang.Long"> <![CDATA[ DELETE FROM t_user WHERE id = #{id} ]]> </update>
The writing method of update operation is similar to that of update operation. If the user id is Long, the specific delete statement is in the element body.
Call SqlSession.update method to perform update operation
SqlSession.delete method needs to be called:
int delete(String statement, Object parameter)
This method has two parameters:
statement: indicates which operation. The value is the namespace of Mapper xml. The id of the specific operation. If you need to call the deleteUser operation in UserMapper.xml, the value is:
com.javacode2018.chat02.UserMapper.
Parameter: the parameter of delete operation is the same as the type specified by parameterType in delete in Mapper xml.
The return value is the number of rows affected by delete.
A new test case is added to the UserTest class:
@Test public void deleteUser() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) { //Define the user id to be deleted Long userId = 1L; //Perform delete operation int result = sqlSession.delete("com.javacode2018.chat02.UserMapper.deleteUser", userId); log.info("Number of affected lines:{}", result); } }
Operation output:
24:45.427 [main] DEBUG c.j.chat02.UserMapper.deleteUser - ==> Preparing: DELETE FROM t_user WHERE id = ? 24:45.476 [main] DEBUG c.j.chat02.UserMapper.deleteUser - ==> Parameters: 1(Long) 24:45.485 [main] DEBUG c.j.chat02.UserMapper.deleteUser - <== Updates: 1 24:45.485 [main] INFO com.javacode2018.chat02.UserTest - Number of affected lines: 1
Execution query
Requirement: query all user information
Select operation defined in UserMapper.xml
<!-- select Used to define a query operation id: Specific identification of operation resultType: Specify the type of query results saved --> <select id="getUserList" resultType="com.javacode2018.chat02.UserModel"> <![CDATA[ SELECT * FROM t_user ]]> </select>
The writing method of update operation is similar to that of update operation. Specify id ID id, parameterType to specify parameter type of operation, resultType to specify type of query result, and specific select statement is in element body.
Call SqlSession.select method to perform update operation
UserTest adds a use case:
@Test public void getUserList() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) { //Perform query operation List<UserModel> userModelList = sqlSession.selectList("com.javacode2018.chat02.UserMapper.getUserList"); log.info("Result:{}", userModelList); } }
Insert several more lines, and then run the above use case. The output is as follows:
36:39.015 [main] DEBUG c.j.chat02.UserMapper.getUserList - ==> Preparing: SELECT * FROM t_user 36:39.048 [main] DEBUG c.j.chat02.UserMapper.getUserList - ==> Parameters: 36:39.066 [main] DEBUG c.j.chat02.UserMapper.getUserList - <== Total: 3 36:39.067 [main] INFO com.javacode2018.chat02.UserTest - UserModel(id=2, name=javacode2018, age=30, salary=50000.0, sex=1) 36:39.069 [main] INFO com.javacode2018.chat02.UserTest - UserModel(id=1575621274235, name=Passerby a Java, age=30, salary=50000.0, sex=1) 36:39.069 [main] INFO com.javacode2018.chat02.UserTest - UserModel(id=1575621329823, name=Passerby a Java, age=30, salary=50000.0, sex=1)
Use of Mapper interface
Why Mapper interface is needed
We explained the operation of adding, deleting, modifying and querying a table by calling methods in SqlSession. Let's take a look at the definitions of several methods just used in SqlSession interface:
int insert(String statement, Object parameter); int update(String statement, Object parameter); int delete(String statement, Object parameter); <E> List<E> selectList(String statement);
The characteristics of these methods are as follows:
-
To call these methods, you need to know the value of statement clearly. The value of statement is namespace. The id of specific operation needs to be opened in Mapper xml to check. It's inconvenient to write
-
parameter parameters are of Object type. We don't know the specific type of this operation at all. We need to check Mapper xml to know. Pass a value casually. The types may not match, but we only know there is a problem when running
-
The selectList method returns a generic type. Through this method, we don't know the specific type of the returned result at all. We also need to check Mapper xml to know
The above points are not very convenient to use. Is there any way to solve these problems?
Yes, this is the Mapper interface in mybatis. We can define an interface and associate it with Mapper xml. The operations in Mapper xml will be bound with the methods in Mapper interface. When we call the methods in Mapper interface, we will indirectly call the operations in Mapper xml. The complete class name of the interface needs to be consistent with the namespace in Mapper xml.
Mapper interface usage (three steps)
Step 1: define Mapper interface
Take a look at the namespace in UserMapper.xml. It is:
<mapper namespace="com.javacode2018.chat02.UserMapper">
The complete name of the interface we created needs to be the same as the value of the namespace above. Next, we create an interface com.javacode2018.chat02.UserMapper, as follows:
package com.javacode2018.chat02; /** * The official account: Java, a former passerby, worked for 10 years before Ali P7 shared Java, algorithm and database technology dry cargo. Strong credit technology changes the fate, let the family live a more decent life! */ public interface UserMapper { }
There are four operations in UserMapper.xml. We need to define four operations in the UserMapper interface, corresponding to the four operations in UserMapper.xml, as follows:
package com.javacode2018.chat02; import java.util.List; /** * The official account: Java, a former passerby, worked for 10 years before Ali P7 shared Java, algorithm and database technology dry cargo. Strong credit technology changes the fate, let the family live a more decent life! */ public interface UserMapper { int insertUser(UserModel model); int updateUser(UserModel model); int deleteUser(Long userId); List<UserModel> getUserList(); }
Four methods are defined in the UserMapper interface. The name of the method needs to be the same as the id value of the specific operation of UserMapper.xml. In this way, when the method in the UserMapper interface is called, the specific operation in UserMapper.xml will be found correspondingly.
For example, if you call the insertUser method in the UserMapper interface, the rule for mybatis to find the corresponding operation in Mapper xml through the full name and method name of the interface.
Step 2: get Mapper interface object through SqlSession
There is a getMapper method in SqlSession, which can pass in the type of interface and get the specific Mapper interface object, as follows:
/** * Retrieves a mapper. * @param <T> the mapper type * @param type Mapper interface class * @return a mapper bound to this SqlSession */ <T> T getMapper(Class<T> type);
For example, get the UserMapper interface object:
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Step 3: call the method of Mapper interface to operate on db
For example, to call the insert operation of the UserMapper interface:
@Test public void insertUser() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); //Create UserModel object UserModel userModel = UserModel.builder().id(System.currentTimeMillis()).name("Passerby a Java").age(30).salary(50000D).sex(1).build(); //Perform insert operation int insert = mapper.insertUser(userModel); log.info("Number of affected lines:{}", insert); } }
Case: use Mapper interface to add, delete, modify and query
Create a test class in chat02/src/test/java. The code is as follows:
package com.javacode2018.chat02; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; /** * The official account: Java, a former passerby, worked for 10 years before Ali P7 shared Java, algorithm and database technology dry cargo. Strong credit technology changes the fate, let the family live a more decent life! */ @Slf4j public class UserMapperTest { private SqlSessionFactory sqlSessionFactory; @Before public void before() throws IOException { //Specify mybatis global profile String resource = "mybatis-config.xml"; //Read global profile InputStream inputStream = Resources.getResourceAsStream(resource); //Building SqlSessionFactory objects SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); this.sqlSessionFactory = sqlSessionFactory; } @Test public void insertUser() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); //Create UserModel object UserModel userModel = UserModel.builder().id(System.currentTimeMillis()).name("Passerby a Java").age(30).salary(50000D).sex(1).build(); //Perform insert operation int insert = mapper.insertUser(userModel); log.info("Number of affected lines:{}", insert); } } @Test public void updateUser() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); //Create UserModel object UserModel userModel = UserModel.builder().id(1L).name("Passerby a Java,Hello").age(18).salary(5000D).sex(0).build(); //Perform update operation int result = mapper.updateUser(userModel); log.info("Number of affected lines:{}", result); } } @Test public void deleteUser() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); //Define the user id to be deleted Long userId = 1L; //Perform delete operation int result = mapper.deleteUser(userId); log.info("Number of affected lines:{}", result); } } @Test public void getUserList() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); //Perform query operation List<UserModel> userModelList = mapper.getUserList(); userModelList.forEach(item -> { log.info("{}", item); }); } } }
Take a look at the above code carefully. This time, we use UserMapper to indirectly call the corresponding operation in UserMapper.xml. You can run it to feel the effect.
Some points for attention when using Mapper interface
-
The complete class name of Mapper interface must be consistent with the value of namespace in the corresponding Mapper xml
-
The name of the method in Mapper interface should be consistent with the id value of the specific operation in Mapper xml
-
The parameters and return values of methods in Mapper interface can not be consistent with those in Mapper xml
The principle of Mapper interface
This is implemented by using the dynamic Proxy in Java. When mybatis starts, the global configuration file mybatis-config.xml will be loaded, and then the user mapper.xml specified by the mapper element in this file will be parsed. According to the namespace value of UserMapper.xml, a dynamic Proxy of this interface will be created. Specifically, you can see the source code of mybatis, which is mainly implemented by using the Proxy in Java, Using the newProxyInstance method in the java.lang.reflect.Proxy class, we can create a Proxy object for any interface:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
We use Proxy to simulate the implementation of Mapper interface:
package com.javacode2018.chat02; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.List; /** * The official account: Java, a former passerby, worked for 10 years before Ali P7 shared Java, algorithm and database technology dry cargo. Strong credit technology changes the fate, let the family live a more decent life! */ @Slf4j public class ProxyTest { public static class UserMapperProxy implements InvocationHandler { private SqlSession sqlSession; private Class<?> mapperClass; public UserMapperProxy(SqlSession sqlSession, Class<?> mapperClass) { this.sqlSession = sqlSession; this.mapperClass = mapperClass; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { log.debug("invoke start"); String statement = mapperClass.getName() + "." + method.getName(); List<Object> result = sqlSession.selectList(statement); log.debug("invoke end"); return result; } } private SqlSessionFactory sqlSessionFactory; @Before public void before() throws IOException { //Specify mybatis global profile String resource = "mybatis-config.xml"; //Read global profile InputStream inputStream = Resources.getResourceAsStream(resource); //Building SqlSessionFactory objects SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); this.sqlSessionFactory = sqlSessionFactory; } @Test public void test1() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) { UserMapper userMapper = (UserMapper) Proxy.newProxyInstance(ProxyTest.class.getClassLoader(), new Class[]{UserMapper.class}, new UserMapperProxy(sqlSession, UserMapper.class)); log.info("{}", userMapper.getUserList()); } } }
In the above code: UserMapper has no implementation class. You can create a proxy object for the UserMapper interface through Proxy.newProxyInstance. When you call the method of the UserMapper interface, you will call the invoke method of the UserMapperProxy object.
Run the test1 case, and the output is as follows:
16:34.288 [main] DEBUG com.javacode2018.chat02.ProxyTest - invoke start 16:34.555 [main] DEBUG c.j.chat02.UserMapper.getUserList - ==> Preparing: SELECT * FROM t_user 16:34.580 [main] DEBUG c.j.chat02.UserMapper.getUserList - ==> Parameters: 16:34.597 [main] DEBUG c.j.chat02.UserMapper.getUserList - <== Total: 4 16:34.597 [main] DEBUG com.javacode2018.chat02.ProxyTest - invoke end 16:34.597 [main] INFO com.javacode2018.chat02.ProxyTest - [UserModel(id=2, name=javacode2018, age=30, salary=50000.0, sex=1), UserModel(id=1575621274235, name=Passerby a Java, age=30, salary=50000.0, sex=1), UserModel(id=1575621329823, name=Passerby a Java, age=30, salary=50000.0, sex=1), UserModel(id=1575623283897, name=Passerby a Java, age=30, salary=50000.0, sex=1)]
Note the above output of invoke start and invoke end. You can see that when we call userMapper.getUserList, it is processed by the usermapperproxy ා invoke method.
The following class is used to create Mapper interface proxy object in Mybatis. You can study it:
public class MapperProxyFactory<T> { private final Class<T> mapperInterface; private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>(); public MapperProxyFactory(Class<T> mapperInterface) { this.mapperInterface = mapperInterface; } public Class<T> getMapperInterface() { return mapperInterface; } public Map<Method, MapperMethod> getMethodCache() { return methodCache; } @SuppressWarnings("unchecked") protected T newInstance(MapperProxy<T> mapperProxy) { return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); } public T newInstance(SqlSession sqlSession) { final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } }