This is the 3rd mybatis series. Did not see the previous article to go to [Java tomb Fox] public number to view the previous article, easy to understand and master

MyBatis usage details

In the previous part, we manually developed a MyBatis project, but we just wrote the code, and did not carefully analyze and explain how the whole project works and the meaning of each code, so we will start to analyze the meaning of each code and how to write this code

Configure the MyBatis global profile

If you want to use Mybatis to operate on a database, then of course you need to configure the database information. This needs to be done in the Mybatis global configuration file. That is, the XML file of global configuration, which supports the transaction of the whole MyBatis and configures information such as database configuration. We usually put it in the main/ Resource file, as shown below

<configuration> <! <environments default="chat01"> <! Id: unique --> <environment id="chat01"> <! - the transaction manager factory configuration - > < transactionManager type = "org. Apache. Ibatis. Transaction. JDBC. JdbcTransactionFactory" / > <! Data source factory configuration, Use the factory to create the data source - > < dataSource type = "org. Apache. Ibatis. The dataSource. Pooled. PooledDataSourceFactory" > < property name = "driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatisdemo? characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> </configuration>Copy the code

The configuration element

This is the root element of the MyBatis global profile, and there is only one for each profile

Environments elements

The environment information used to configure mybatis is used to configure multiple environments. A specific environment is configured using the Environment element. The environment element has an ID to identify a specific environment.

The Environments element has a default attribute that specifies which environment to use by default, such as chat01.

The environment elements

Used to configure specific environment information, this element has two child elements: transactionManager and dataSource

  • TransactionManager elements

Used to configure the affairs of the factory, there was a type attribute, the type of value must be org. Apache. The ibatis. Transaction. TransactionFactory interface implementation class, used to create the transaction manager object, The TransactionFactory interface has two implementations by default:

org.apache.ibatis.transaction.managed.ManagedTransactionFactory
org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory
Copy the code

Normally we use org. Apache. Ibatis. Transaction. JDBC. JdbcTransactionFactory this, mybatis and other framework integration, such as the spring integration, transaction to the spring to control.

  • The dataSource element

This used to configure the data source, the type attribute value must be a interface org. Apache. The ibatis. The datasource. DataSourceFactory implementation class, DataSourceFactory is also a factory, Mybatis: javax.sql.DataSource: javax.sql.DataSource: javax.sql.DataSource: javax.sql.DataSource

org.apache.ibatis.datasource.jndi.JndiDataSourceFactory
org.apache.ibatis.datasource.pooled.PooledDataSourceFactory
org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory
Copy the code

We use the second org. Apache. Ibatis. The datasource. Pooled. PooledDataSourceFactory, this used to create a database connection pool types of data sources, can realize the database connection sharing, reduce the time of the connection repeatedly creating destroyed. DataSource = ‘dataSource’; dataSource = ‘dataSource’; dataSource = ‘dataSource’;

<property name=" property name "value=" value "/>Copy the code

Create the Mapper XML file

In Mybatis, we generally write all SQL operations of a table in a Mapper XML, generally named xxxmapper.xml format.

As follows:

<? The 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="zhonghu.mybatis.chat01.UserMapper"> </mapper>Copy the code

The root element of mapper XML is mapper, which has a namespace attribute. There will be many tables in the system, and each table corresponds to a Mapper XML. In order to prevent the mapper XML file from repeating, we need to specify a namespace for each mapper XML file. Through this can distinguish between each mapper XML file, on which we appointed zhonghu. Mybatis. Chat01. UserMapper.

We will write the SQL associated with all operations on the user table in this XML.

Mapper XML file is introduced in mybatis global configuration file

Mybatis -config. XML (usermapper. XML);

<mappers>
        <mapper resource="mapper/user.xml"/>
    </mappers>
Copy the code

There are multiple Mapper elements under the Mappers element, which can be imported into the Mapper XML file through the Resource attribute of the Mapper element, which is the path relative to classes.

Mybatis (myBatis) : MyBatis (MyBatis) : MyBatis (MyBatis)

Build the SqlSessionFactory object

// Specify mybatis global configuration file String resource = "mybatis-config.xml"; / / read global configuration file InputStream InputStream = Resources. The getResourceAsStream (resource); SqlSessionFactory SqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);Copy the code

SqlSessionFactory is an interface. It is a heavyweight object. The SqlSessionFactoryBuilder reads the global configuration file to create an SqlSessionFactory. SqlSessionFactoryBuilder creates a complex SqlSessionFactory object by parsing the myBatis global configuration file. The life cycle of this object is generally the same as the life cycle of the application. It is created when the application is started and ends when the application is stopped. Therefore, it is generally a global object.

Build the SqlSession object

SqlSession is a JDBC Connection object, which is equivalent to a database Connection. You can use SqlSession to operate on db: SqlSessionFactory creates a SqlSession object using the following methods:

SqlSession openSession(); // Create a SqlSession. SqlSession openSession(Boolean autoCommit); SqlSession openSession(Boolean autoCommit);Copy the code

SqlSession interface many methods, directly used to operate db, method list as follows, we familiar with:

<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();

Copy the code

SQL > select select from db, insert from DB, update from DB, update from DB.

Introducing Lombok support (optional)

Lombok can simplify Java code in the form of simple annotations to improve developer productivity. For example, javabeans often need to be written in development. It takes time to add corresponding getters/setters, and maybe to write constructors, equals, etc. Besides, they need to be maintained. When there are too many properties, a large number of getters/setters will appear. Once an attribute is modified, it is easy to forget to modify the corresponding method.

Lombok automatically generates constructors, getters/setters, equals, hashcode, and toString methods for properties at compile time via annotations. The magic that happens is that there are no getters and setters in the source code, but there are getters and setters in the bytecode files generated by the compilation. This saves you the trouble of manually rebuilding the code and makes it look cleaner.

Steps to use Lombok

  • To open the idea, go to File->Settings->plugins, search for lombok Plugin, and click Install.
  • Introduction of Lombok support in Maven
< the dependency > < groupId > org. Projectlombok < / groupId > < artifactId > lombok < / artifactId > < version > 1.18.10 < / version > <scope>provided</scope> </dependency>Copy the code
  • Use Lombok-related functionality in your code

Introducing logbacks (optional)

In order to conveniently view the log generated in the running process of Mybatis, such as: SQL execution, 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, we use this here

Integrate logback step in Mybatis

  • Logback support was introduced in Maven
< the dependency > < groupId > ch. Qos. Logback < / groupId > < artifactId > logback - classic < / artifactId > < version > 1.2.3 < / version > </dependency>Copy the code
  • Create logback. XML file from SRC /main/resources:
<? The 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="zhonghu" level="debug" additivity="false"> <appender-ref ref="STDOUT" /> </logger> </configuration>Copy the code

It is beyond the scope of this article to write logback. XML. If you are interested, you can explore the use of logback.

Write a test case

With all that said, let’s write a test class to demonstrate

As follows:

package zhonghu.mybatis.chat01; 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 UserMapperTest { private SqlSessionFactory sqlSessionFactory; @before public void Before () throws IOException {// Specify mybatis global configuration file String resource = "mybatis-config.xml"; / / read global configuration file InputStream InputStream = Resources. The getResourceAsStream (resource); SqlSessionFactory SqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); this.sqlSessionFactory = sqlSessionFactory; } @Test public void sqlSession() { SqlSession sqlSession = this.sqlSessionFactory.openSession(); log.info("{}", sqlSession); }}Copy the code

There is an @slf4J annotation in the above code, which lombok provides, to generate the following code in this class:

private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(UserTest.class);

Copy the code

Run the sqlSession method, which produces the following output:

37:52. 473. [the main] INFO z.m ybatis. Chat01. UserMapperTest - org. Apache. Ibatis. Session. The defaults. 2 d127a61 DefaultSqlSession @Copy the code

So far we have built a minimal Mybatis project, then we need to write our SQL files according to the needs

SQL operations are performed using SqlSesion

Common usage of SqlSession

SqlSession is equivalent to a connection, you can use this object to add, delete, change and check db operations, after the operation needs to close, use the procedure:

  • Get SqlSession objects: through the sqlSessionFactory obtained openSession SqlSession objects
  • Perform operations on the DB: Perform operations on the DB using the SqlSession object
  • Close the SqlSession object: sqlsession.close ();

As shown below.

/ / get SqlSession SqlSession SqlSession = this. SqlSessionFactory. OpenSession (); Try {// Perform service operations, such as: add, delete, change, and check} finally {// close SqlSession SQLsession.close (); }Copy the code

Above we put the closing of the SqlSession ina finally block to ensure that close() will always execute.

The new operation

Requirement: Pass in the UserModel object and insert the object’s data into the User table.

Create a UserModel

UserModel class, code as follows:

package zhonghu.mybatis.chat01;

import lombok.*;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
public class UserModel {
    private Long id;
    private String name;
    private Integer age;
    private Double salary;
}

Copy the code

The fields of this class correspond to the user table.

Insert operations are defined in user.xml

As we said, all SQL operations on the user table are placed in user.xml. We add the following configuration to user.xml to define the insert operations using the insert element:

<! ParameterType specifies the id of an insert operation. Specify the parameters of the insert accept type - > < insert id = "insertUser" parameterType = "zhonghu. Mybatis. Chat01. UserModel" > <! [CDATA[ INSERT INTO user (id,name,age,salary) VALUES (#{id},#{name},#{age},#{salary}) ]]> </insert>Copy the code
  • The INSERT element is used to define an insert operation into the DB
  • Id: is an identifier for this operation. The namespace and ID will be used to refer to the insert operation when performing operations on Mybatis.
  • ParameterType: Specifies the types of arguments to be accepted for the insert operation. It can be Java objects of various Javabeans, Maps, lists, and collections. Our insert accepts a UserModel object.
  • The insert element internally defines a specific SQL, as seen in an INSERT SQL, that inserts data into the USER table.

The values that need to be inserted are retrieved from the UserModel object. Take the fields of the UserModel object and use the format #{fields} to get the values of the fields in UserModel.

The sqlsession. insert method is called to perform the insert operation

The SQL inserted by user is already written in UserMapper.

The sqlsession.insert method is called:

int insert(String statement, Object parameter)

Copy the code

This method takes two arguments:

  • Statement: indicates the operation and its value is the namespace of Mapper XML. The id of the specific operation, such as the insertUser operation in usermapper. XML, would be:
zhonghu.mybatis.chat01.UserMapper.insertUser

Copy the code
  • Parameter: specifies the parameter of an insert operation, the same type as parameterType specified in INSERT in Mapper XML.

The return value is the number of inserted rows.

Add a new test case to the UserTest class:

@Test public void insertUser() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(false);) UserModel UserModel = userModel.builder ().id(69L).name("Java Tomb Fox ").age(30).salary(50000D).build(); / / perform insert int result = sqlSession. Insert (" zhonghu. Mybatis. Chat01. UserMapper. InsertUser ", userModel); Log.info (" insert affects rows: {}", result); // commit transaction sqlSession.com MIT (); }}Copy the code

Run the following output:

05:15. 831. [the main] the DEBUG Z.M.C hat01. UserMapper. InsertUser - = = > Preparing: INSERT INTO user (id, name, age, salary) VALUES (?,?,?,?,? ,? ,? ,?) 05:15. 853. [the main] the DEBUG Z.M.C hat01. UserMapper. InsertUser - = = > the Parameters: 69(Long), Java Mound Fox (String), 30(Integer), 50000.0 (Double) 05:15. 951. [the main] the DEBUG Z.M.C hat01. UserMapper. InsertUser - < = = Updates: 1 05:15. [the main] 952 INFO z.m ybatis. Chat01. UserMapperTest - insert influence lines: 1Copy the code

The output prints the detailed SQL statement, along with the parameter information of the SQL. You can see that the #{} in Mapper XML is replaced by? , which uses the PreparedStatement in JDBC to set the parameter values.

The second line in the output details the values of the parameters and the type of each value.

The third line outputs an INSERT result of 1, indicating that 1 row was successfully inserted.

Create SqlSession in the code above, we use the sqlSessionFactory. OpenSession (), created by this method to create SqlSession, internal affairs is a way of automatic submission so we need to manually submit:

Add, delete, and modify all require a transaction to be committed

sqlSession.commit();

Copy the code

If you want to automatically commit the transaction, in the above sqlSessionFactory instead. When creating SqlSession openSession (true), specify the transaction for the autocommit mode, so finally we don’t need to manually commit the transaction.

The update operation

Requirement: Pass in the UserModel object and update the data by ID.

The Update operation is defined in usermapper.xml

Use update to define an update operation:

<! ParameterType: specifies the id of an update operation. At the operating parameter types - > < the update id = "updateUser" parameterType = "zhonghu. Mybatis. Chat01. UserModel" > <! [CDATA[ UPDATE user SET name = #{name},age = #{age},salary = #{salary} WHERE id = #{id} ]]> </update>Copy the code

ParameterType specifies the parameterType of the operation. The element body contains the specific SQL statement.

Call the sqlsession. update method to perform the update operation

Call the sqlsession. update method:

int update(String statement, Object parameter)

Copy the code

This method takes two arguments:

  • Statement: Indicates the operation. The value is the namespace of Mapper XML. The id of the specific operation, such as the call to the updateUser operation in usermapper. XML, would be:
zhonghu.mybatis.chat01.UserMapper.updateUser

Copy the code
  • Parameter: specifies the parameter for the update operation. This parameter is the same type as parameterType specified in Update in Mapper XML.

The return value is the number of rows affected by update.

Add a new test case to the UserTest class:

@Test public void updateUser() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) UserModel UserModel = userModel.builder ().id(1L).name("Java Mound Fox, hello ").age(18).salary(5000D).build(); / / update operations int result = sqlSession. Update (" zhonghu. Mybatis. Chat01. UserMapper. UpdateUser ", userModel); Log.info (" effect number of rows: {}", result); }}Copy the code

Run output:

. 12:17. 143. [the main] the DEBUG Z.M.C hat01 UserMapper. UpdateUser - = = > Preparing: UPDATE the user SET name =? ,age = ? ,salary = ? WHERE id = ? . 12:17. 163. [the main] the DEBUG Z.M.C hat01 UserMapper. UpdateUser - = = > the Parameters: Fox Java burial. Hello (String), 18 (Integer), 5000.0 (Double), 1 (Long) but 258 [main] the DEBUG Z.M.C hat01. UserMapper. UpdateUser - < = = Updates: 1. 12:17 and 258 [the main] INFO z.m ybatis. Chat01. UserMapperTest - affect the number of lines: 1Copy the code

Delete operation

Requirement: Delete user records based on the user ID

The Delete operation is defined in usermapper.xml

Use the update element to define the delete operation:

<! ParameterType: specifies the parameters to be used for the operation --> <update ID ="deleteUser" parameterType="java.lang.Long"> <! [CDATA[ DELETE FROM user WHERE id = #{id} ]]> </update>Copy the code

ParameterType specifies the parameterType of the operation. If the user id is Long, the element body contains the delete statement.

Call the sqlsession. update method to perform the update operation

The sqlsession. delete method is called:

int delete(String statement, Object parameter)

Copy the code

This method takes two arguments:

  • Statement: Indicates the operation. The value is the namespace of Mapper XML. The id of the specific operation, such as the deleteUser operation in usermapper. XML, would be:
com.javacode2018.chat02.UserMapper.

Copy the code
  • Parameter: parameter of the delete operation, consistent with the type specified by parameterType in delete in Mapper XML.

The return value of delete affects the number of rows.

Add a new test case to the UserTest class:

@Test public void deleteUser() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {// define the userId to be deleted Long userId = 1L; / / delete operations int result = sqlSession. Delete (" zhonghu. Mybatis. Chat01. UserMapper. DeleteUser ", userId); Log.info (" effect number of rows: {}", result); }}Copy the code

Run output:

. 14:26. 711. [the main] the DEBUG Z.M.C hat01 UserMapper. DeleteUser - = = > Preparing: The DELETE FROM the user WHERE id =? 14:26. 729 [main] the DEBUG Z.M.C hat01. UserMapper. DeleteUser - = = > the Parameters: 1 (Long) 14:26. 811. [the main] the DEBUG Z.M.C hat01. UserMapper. DeleteUser - < = = Updates: 1. 14:26 812 [main] INFO z.m ybatis. Chat01. UserMapperTest - affect the number of lines: 1Copy the code

Execute the query

Select statements have endor attributes to configure each SQL statement in detail

  • SQL statement return value type [full class name or alias]
  • The type of parameter passed into the SQL statement
  • A unique identifier in a namespace
  • The method name in the interface corresponds to the SQL statement ID in the mapping file

Requirement: Query information about all users

Select operations are defined in usermapper.xml

<! -- select specifies a query operation id. ResultType: Specify the type of the query results - > < select id = "getUserList resultType" = "zhonghu. Mybatis. Chat01. UserModel" > <! [CDATA[ SELECT * FROM user ]]> </select>Copy the code

ParameterType specifies the parameterType of the operation. ResultType specifies the type of the query result. The element body contains the select statement.

Call the sqlsession. select method to perform the update operation

UserTest adds a use case:

@Test public void getUserList() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {/ / perform query operations List < UserModel > userModelList = sqlSession. SelectList (" zhonghu. Mybatis. Chat01. UserMapper. GetUserList "); Log.info (" result: {}", userModelList); }}Copy the code

Insert a few more lines and run the above use case, with the following output:

16:00. 798. [the main] the DEBUG Z.M.C hat01. UserMapper. GetUserList - = = > Preparing: SELECT * FROM user 16:00. 817. [the main] the DEBUG Z.M.C hat01. UserMapper. GetUserList - = = > the Parameters: 16:00. 829. [the main] the DEBUG Z.M.C hat01. UserMapper. GetUserList - < = = Total: 16 16:00. 829. [the main] INFO z.m ybatis. Chat01. UserMapperTest - result: [UserModel(id=2, name= salary, age=23, salary=50000.0), UserModel(id=3, name= salary, age=24, salary=6666.66), UserModel(id=4, name=Mybatis-1, age=19, salary=10000.0), UserModel(id=5, name=Mybatis-1, age=25, salary=20000.0), UserModel(id=6, name=Mybatis- 1, age=20, salary=20000.0), UserModel(id=7, name=Mybatis-2, age=20, salary=20000.0), UserModel(id= 4, name=Mybatis-3, age=21, salary=40000.0), UserModel(id= 5, name=Mybatis-3, age=21, salary=40000.0), UserModel(id=10, name=Mybatis-4, age=22, salary=50000.0), UserModel(id=10, name=Mybatis-4, age=22, salary=50000.0), UserModel(id= 10, name=Mybatis-5, age= 10, salary=50000.0), UserModel(id= 10, name=Mybatis-5, age= 10, salary=50000.0), UserModel(id, name, age, salary=50000.0), UserModel(id, name, age, salary=50000.0), UserModel(id=89, name= name, age=30, salary=50000.0), UserModel(id=89, name= name, age=30, salary=50000.0)]Copy the code

Use of Mapper interfaces

Why do I need a Mapper interface

We explained the above for a table to add and delete operations, it is the method to invoke the SqlSession to complete, you look at the SqlSession in the interface definition of just used several methods:

int insert(String statement, Object parameter);
int update(String statement, Object parameter);
int delete(String statement, Object parameter);
<E> List<E> selectList(String statement);

Copy the code

Let’s take a look at the characteristics of these methods:

  • To call these methods, you need to know the value of Statement, which is namespace. The id of the specific operation, which you need to open Mapper XML to see, is not easy to write
  • Parameter is a parameter of type Object. We don’t know what type this operation is. We need to look at Mapper XML
  • The selectList method returns a generic type, so we don’t know the exact type of the returned result at all. We need to look at Mapper XML to find out

These are all inconvenient situations in the process of use. If you want to use them conveniently, you need to use Mapper interface in Mybatis. We can define an interface and then associate it with Mapper XML. When we call the methods of Mapper interface, we will indirectly call the operations in Mapper XML. The full class name of the interface must be the same as the namespace in Mapper XML.

Mapper Interface usage (three steps)

Step 1: Define the Mapper interface

Take a look at the namespace in user.xml, which is:

<mapper namespace="zhonghu.mybatis.chat01.UserMapper">

Copy the code

The full name of the interface we create needs to be the same as the namespace value above. Let’s create an interface named UserMapper as follows:

There are 4 operations in usermapper. XML, we need to define 4 operations in UserMapper interface, corresponding to the 4 operations in usermapper. XML, as follows:

package zhonghu.mybatis.chat01;
import java.util.List;

public interface UserMapper {
    int insertUser(UserModel model);
    int updateUser(UserModel model);
    int deleteUser(Long userId);
    List<UserModel> getUserList();
}

Copy the code

The UserMapper interface defines four methods. The names of the methods must be the same as the ID of the specific usermapper. XML operation.

For example, when calling the insertUser method in the UserMapper interface, Mybatis looks for the rule that the full name of the interface is passed. Method name go to Mapper XML to find the corresponding operation.

Step 2: Obtain the Mapper interface object using SqlSession

GetMapper; getMapper; getMapper; getMapper; getMapper; getMapper;

/**
   * 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);

Copy the code

To obtain the UserMapper interface object:

UserMapper mapper = sqlSession.getMapper(UserMapper.class);

Copy the code

Step 3: Call the methods of Mapper interface to operate on DB

For example, calling 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 the UserModel object UserModel UserModel = UserModel. Builder (). The id (System. CurrentTimeMillis ()). The name (" Java burial fox "). The age (30) salary (50000 d). The build (); Int insert = mapper.insertUser(userModel); Log.info (" affected rows: {}", insert); }}Copy the code

Case: use Mapper interface to implement add, delete, change and search

Create a test class with the following code:

package zhonghu.mybatis.chat01; 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; @Slf4j public class UserMapperTest { private SqlSessionFactory sqlSessionFactory; @before public void Before () throws IOException {// Specify mybatis global configuration file String resource = "mybatis-config.xml"; / / read global configuration file InputStream InputStream = Resources. The getResourceAsStream (resource); 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 the UserModel object UserModel UserModel = UserModel. Builder (). The id (System. CurrentTimeMillis ()). The name (" Java burial fox "). The age (30) salary (50000 d). The build (); Int insert = mapper.insertUser(userModel); Log.info (" affected rows: {}", insert); } } @Test public void updateUser() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); UserModel UserModel = userModel.builder ().id(1L).name("Java Mound Fox, hello ").age(18).salary(5000D).build(); Int result = mapper.updateUser(userModel); Log.info (" effect number of rows: {}", result); } } @Test public void deleteUser() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); // define the userId to be deleted Long userId = 1L; Int result = mapper.deleteUser(userId); Log.info (" effect number of rows: {}", result); } } @Test public void getUserList() { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<UserModel> userModelList = mapper.getUserList(); userModelList.forEach(item -> { log.info("{}", item); }); }}}Copy the code

Take a look at the code above. This time we are using UserMapper to indirectly call the corresponding operation in usermapper.xml. You can run it to feel the effect.

Points to note when using Mapper interfaces

  • The full class name of the Mapper interface must match the namespace value in the corresponding Mapper XML
  • The name of the method in the Mapper interface must be the same as the ID of the specific operation in the Mapper XML
  • The parameters and return values of methods in Mapper interface can be different from those in Mapper XML

Principles of Mapper interfaces

This is implemented using dynamic proxies in Java. Mybatis starts with the global configuration file mybatis-config. XML and parses the usermapper.xml specified by the mapper element in this file. Create a dynamic Proxy for this interface according to the namespace value of usermapper. XML, you can go to see mybatis source code, mainly using Java Proxy implementation, Using the newProxyInstance method in the java.lang.reflect.Proxy class, we can create a Proxy object for either interface:

public static Object newProxyInstance(ClassLoader loader, Class<? >[] interfaces, InvocationHandler h)Copy the code

We use Proxy to mimic the implementation of the Mapper interface:

package zhonghu.mybatis.chat01; 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; @Slf4j public class UserMapperTest { 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 configuration file String resource = "mybatis-config.xml"; / / read global configuration file InputStream InputStream = Resources. The getResourceAsStream (resource); 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(UserMapperTest.class.getClassLoader(), new Class[]{UserMapper.class}, new UserMapperProxy(sqlSession, UserMapper.class)); log.info("{}", userMapper.getUserList()); }}}Copy the code

In the code above: UserMapper has no implementation class. You can create a Proxy object for the UserMapper interface through proxy. newProxyInstance. When invoking the method of the UserMapper interface, the invoke method of the UserMapperProxy object will be invoked.

Run the test1 use case and the output looks like this:

29:37. 847. [the main] the DEBUG Z.M.C hat01. UserMapper. GetUserList - = = > Preparing: SELECT * FROM user 29:37. 865. [the main] the DEBUG Z.M.C hat01. UserMapper. GetUserList - = = > the Parameters: 29:37. 878. [the main] the DEBUG Z.M.C hat01. UserMapper. GetUserList - < = = Total: 16 29:37. 878. [the main] the DEBUG z.m ybatis. Chat01. UserMapperTest - invoke end 29:37. [the main] 878 INFO Z.m ybatis. Chat01. UserMapperTest - [UserModel (id = 2, name = modified burial fox, age = 23, salary = 50000.0), UserModel (id = 3, fox name = modified burial, Age =4, salary=6666.66), UserModel(id=4, name=Mybatis-1, age=19, salary=10000.0) Age =25, salary=20000.0), UserModel(id=6, name=Mybatis, age=20, salary=20000.0), UserModel(id=7, name=Mybatis, age=20, name= UserModel), Age = 26, salary = 30000.0), UserModel (id = 8, name = Mybatis 3, age = 21, salary = 30000.0), UserModel (id = 9, name = Java burial fox - 4, Age =4, salary=4), UserModel(id= 5, name= 4, age= 5, salary= 5), UserModel(id= 5, name= 5, age= 5, name= 5), UserModel(id= 5, name= 5, age= 5, name= 5), Age = 28, salary = 50000.0), UserModel (id = 12, name = Mybatis - 5, age = 23, salary = 50000.0), UserModel (id = 13, name = Java burial fox, age = 1, UserModel(id= 50, name= 50, age= 50, salary=50000.0), UserModel(ID =50, name= 50, age= 50, salary=50000.0) UserModel(id=89, name= name, age=30, salary=50000.0), UserModel(id=89, name= name, age=30, salary=50000.0)]Copy the code

Note the invoke Start and Invoke End output above, and you can see that when we call usermapper. getUserList, the UserMapperProxy#invoke method handles it.

Mybatis create Mapper interface proxy object using the following class, you can go to explore:

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); }}Copy the code

The last

  • If you feel that you have gained something after watching it, I hope you can pay attention to it and give me a “like”, which will be the biggest motivation for my update. Thank you for your support
  • Welcome everyone to pay attention to my public number [Java tomb Fox], focus on Java and computer basic knowledge, to ensure that you see something harvest, do not believe you hit me
  • Ask for a key three even: like, forward, look.
  • If you have different opinions or suggestions after reading, welcome to comment together. Thank you for your support and kindness.

I’m Tsuka Fox. I love programming as much as you do.

Please follow the public account “Java Tomb Fox” for the latest news