It's enough for MyBatis to explain in detail

Keywords: Java Mybatis JDBC Apache

Chapter 1 details of MyBatis framework configuration file

1.1 typeHandlers type converter

Whenever MyBatis sets the parameter to PreparedStatement or gets the value from the ResultSet result set, TypeHandler is used to handle the conversion between database type and java type. The following table describes the default

TypeHandlers

1.1.1 custom type converter

Suppose that the field in the table is of type int, and the attribute corresponding to the entity class is of type boolean, then the user-defined type converter can be used for correspondence.

(1) entity class

 1 package com.chenyanbin.beans;
 2 
 3 public class Dept {
 4     private Integer deptNo;
 5     private String dname;
 6     private String loc;
 7     private boolean flag;
 8     public Integer getDeptNo() {
 9         return deptNo;
10     }
11     public boolean isFlag() {
12         return flag;
13     }
14     public void setFlag(boolean flag) {
15         this.flag = flag;
16     }
17     public void setDeptNo(Integer deptNo) {
18         this.deptNo = deptNo;
19     }
20     public String getDname() {
21         return dname;
22     }
23     public void setDname(String dname) {
24         this.dname = dname;
25     }
26     public String getLoc() {
27         return loc;
28     }
29     public void setLoc(String loc) {
30         this.loc = loc;
31     }
32 }

(2) fields in the table

(3) develop custom type converter: MyTypeHandler.java

Inherit and implement interface: TypeHandler.java

 1 package com.chenyanbin.util;
 2 
 3 import java.sql.CallableStatement;
 4 import java.sql.PreparedStatement;
 5 import java.sql.ResultSet;
 6 import java.sql.SQLException;
 7 
 8 import org.apache.ibatis.jdbc.Null;
 9 import org.apache.ibatis.type.JdbcType;
10 import org.apache.ibatis.type.TypeHandler;
11 /*
12  * setParameter:This method is called only when generating SQL statements
13  * 
14  * getResult:When converting a ResultSet data row to an entity class object after the query, inform the TypeHandler what type to convert a field in the current data row
15  * 
16  * 
17  */
18 public class MyTypeHandler implements TypeHandler {
19 
20     public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
21         if (parameter==null) { //dept.flag=null insertsql flag setting 0
22             ps.setInt(i, 0);
23             return;
24         }
25         Boolean flag=(Boolean)parameter;
26         if (flag==true) {
27             ps.setInt(i, 1);
28         }
29         else {
30             ps.setInt(i, 0);
31         }
32     }
33 
34     public Object getResult(ResultSet rs, String columnName) throws SQLException {
35         int flag = rs.getInt(columnName); //1 or 0
36         Boolean myFlag=Boolean.FALSE;
37         if (flag==1) {
38             myFlag=Boolean.TRUE;
39         }
40         return myFlag;
41     }
42 
43     public Object getResult(ResultSet rs, int columnIndex) throws SQLException {
44         // TODO Auto-generated method stub
45         return null;
46     }
47 
48     public Object getResult(CallableStatement cs, int columnIndex) throws SQLException {
49         // TODO Auto-generated method stub
50         return null;
51     }
52 
53 }

(4) register the custom type converter in MyBatis core configuration file:

myBatis-config.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE configuration
 3   PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 4   "http://mybatis.org/dtd/mybatis-3-config.dtd">
 5 <configuration>
 6     <!-- Attribute configuration -->
 7     <properties resource="config.properties"></properties>
 8     <!-- Alias configuration -->
 9     <typeAliases>
10         <package name="com.chenyanbin.beans" />
11         <package name="com.chenyanbin.dao" />
12     </typeAliases>
13     <!-- Type processor -->
14     <typeHandlers>
15         <!-- from java Medium Boolean turn jdbc Medium NUMERIC -->
16         <typeHandler handler="com.chenyanbin.util.MyTypeHandler"
17             javaType="Boolean" jdbcType="NUMERIC" />
18     </typeHandlers>
19     <!-- Environmental configuration -->
20     <environments default="development">
21         <!-- Environmental configuration -->
22         <environment id="development">
23             <!-- Transaction manager -->
24             <transactionManager type="JDBC"></transactionManager>
25             <!-- data source -->
26             <dataSource type="pooled">
27                 <property name="driver" value="${jdbc.driver}" />
28                 <property name="url" value="${jdbc.url}" />
29                 <property name="username" value="${jdbc.username}" />
30                 <property name="password" value="${jdbc.password}" />
31             </dataSource>
32         </environment>
33     </environments>
34     <!-- Mapper -->
35     <mappers>
36         <package name="com.chenyanbin.dao" />
37     </mappers>
38 </configuration>

config.properties

1 jdbc.driver=com.mysql.jdbc.Driver
2 jdbc.url=jdbc:mysql://localhost:3306/sam
3 jdbc.username=root
4 jdbc.password=root

(5) create interface: DeptMapper.java

 1 package com.chenyanbin.dao;
 2 
 3 import java.util.List;
 4 import com.chenyanbin.beans.Dept;
 5 
 6 public interface DeptMapper {
 7     public void deptSave(Dept dept);
 8 
 9     public List<Dept> deptFind();
10 }

(6)  DeptMapper.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE mapper
 3   PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 4   "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 5 <mapper namespace="com.chenyanbin.dao.DeptMapper">
 6     <insert id="deptSave">
 7         insert into dept (DEPTNO,DNAME,LOC,flag)
 8         values(#{deptNo},#{dname},#{loc},#{flag})
 9     </insert>
10     <select id="deptFind" resultType="Dept">
11         select deptNo,dname,loc,flag from dept
12     </select>
13 </mapper>
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE configuration
 3   PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 4   "http://mybatis.org/dtd/mybatis-3-config.dtd">
 5 <configuration>
 6     <!-- Attribute configuration -->
 7     <properties resource="config.properties"></properties>
 8     <!-- Alias configuration -->
 9     <typeAliases>
10         <package name="com.chenyanbin.beans" />
11         <package name="com.chenyanbin.dao" />
12     </typeAliases>
13     <!-- Environmental configuration -->
14     <environments default="development">
15         <!-- Environmental configuration -->
16         <environment id="development">
17             <!-- Transaction Manager -->
18             <transactionManager type="JDBC"></transactionManager>
19             <!-- data source -->
20             <dataSource type="pooled">
21                 <property name="driver" value="${jdbc.driver}" />
22                 <property name="url" value="${jdbc.url}" />
23                 <property name="username" value="${jdbc.username}" />
24                 <property name="password" value="${jdbc.password}" />
25             </dataSource>
26         </environment>
27     </environments>
28     <!-- Mapper -->
29     <mappers>
30         <package name="com.chenyanbin.dao" />
31     </mappers>
32 </configuration>
Mode 2: myBatis-config.xml
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE mapper
 3   PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 4   "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 5 <mapper namespace="com.chenyanbin.dao.DeptMapper">
 6     <insert id="deptSave">
 7         insert into dept (DEPTNO,DNAME,LOC,flag)
 8         values(#{deptNo},#{dname},#{loc},#{flag})
 9     </insert>
10     <resultMap type="dept" id="deptMap">
11     <result column="flag" property="flag" typeHandler="com.chenyanbin.util.MyTypeHandler"/>
12     </resultMap>
13     <select id="deptFind" resultType="Dept">
14         select deptNo,dname,loc,flag from dept
15     </select>
16 </mapper>
Mode 2: DeptMapper.xml

(7) execute unit test: testmain menu 01.java

 1 package com.chenyanbin.test;
 2 
 3 import java.io.IOException;
 4 import java.io.InputStream;
 5 import java.util.List;
 6 import org.apache.ibatis.io.Resources;
 7 import org.apache.ibatis.session.SqlSession;
 8 import org.apache.ibatis.session.SqlSessionFactory;
 9 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
10 import org.junit.After;
11 import org.junit.Before;
12 import org.junit.Test;
13 import com.chenyanbin.beans.Dept;
14 import com.chenyanbin.dao.DeptMapper;
15 
16 public class TestMain_01 {
17     private SqlSession session;
18 
19     @Before
20     public void Start() {
21         try {
22             InputStream inputStream = Resources.getResourceAsStream("myBatis-config.xml");
23             SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
24             session = factory.openSession();
25         } catch (Exception e) {
26             e.printStackTrace();
27         }
28     }
29 
30     @After
31     public void end() {
32         if (session == null) {
33             session.close();
34         }
35     }
36 
37     @Test
38     public void test01() throws IOException {
39         Dept d2 = new Dept();
40         d2.setDname("Shanghai Business Department");
41         d2.setLoc("Shanghai");
42         d2.setFlag(false);
43         session.insert("deptSave", d2);
44         session.commit();
45         session.close();
46     }
47 
48     @Test
49     public void test02() {        
50           DeptMapper dao=session.getMapper(DeptMapper.class);
51           List<Dept> deptList=dao.deptFind();
52           System.out.println("ok");         
53     }
54 
55 }

(8) project directory structure

1.2 objectFactory

Every time MyBatis creates a new instance of the resulting object, it uses an object factory instance to do so. The default object factory only needs to instantiate the target class, either through the default constructor or through the parameter constructor when the parameter mapping exists. If you want to override the default behavior of an object factory, you can do so by creating your own object factory.

1.2.1 custom object factory

Table structure: dept

Entity class: Dept.java

 1 package com.chenyanbin.beans;
 2 
 3 public class Dept {
 4     private Integer deptNo;
 5     private String dname;
 6     private String loc;
 7     private Boolean flag;
 8     private String country;
 9     public String getCountry() {
10         return country;
11     }
12     public void setCountry(String country) {
13         this.country = country;
14     }
15     public Integer getDeptNo() {
16         return deptNo;
17     }
18     public Boolean getFlag() {
19         return flag;
20     }
21     public void setFlag(Boolean flag) {
22         this.flag = flag;
23     }
24     public void setDeptNo(Integer deptNo) {
25         this.deptNo = deptNo;
26     }
27     public String getDname() {
28         return dname;
29     }
30     public void setDname(String dname) {
31         this.dname = dname;
32     }
33     public String getLoc() {
34         return loc;
35     }
36     public void setLoc(String loc) {
37         this.loc = loc;
38     }
39 }

(1) inheritance and DefaultObjectFactory: MyObjectFactory.java

 1 package com.chenyanbin.util;
 2 
 3 import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
 4 
 5 import com.chenyanbin.beans.Dept;
 6 
 7 public class MyObjectFactory extends DefaultObjectFactory {
 8 
 9     @Override
10     public Object create(Class type) {// Redefinition Dept Class instance object creation rules, other class instance object creation rules do not want to change
11         if (Dept.class == type) {
12             // Dependent on parent class create Method creation Dept object
13             Dept dept = (Dept) super.create(type);
14             // Set custom rules
15             dept.setCountry("China");
16             return dept;
17         }
18         return super.create(type);
19     }
20 
21 }

(2) register custom factory in MyBatis core file

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE configuration
 3   PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 4   "http://mybatis.org/dtd/mybatis-3-config.dtd">
 5 <configuration>
 6     <!-- Attribute configuration -->
 7     <properties resource="config.properties"></properties>
 8     <!-- Alias configuration -->
 9     <typeAliases>
10         <package name="com.chenyanbin.beans" />
11         <package name="com.chenyanbin.dao" />
12     </typeAliases>
13     <!-- ObjectFactory Object factory -->
14     <objectFactory type="com.chenyanbin.util.MyObjectFactory"></objectFactory>
15     <!-- Type processor -->
16 <!--     <typeHandlers>
17         from java Medium Boolean turn jdbc Medium NUMERIC
18         <typeHandler handler="com.chenyanbin.util.MyTypeHandler"
19             javaType="Boolean" jdbcType="NUMERIC" />
20     </typeHandlers> -->
21     <!-- Environmental configuration -->
22     <environments default="development">
23         <!-- Environmental configuration -->
24         <environment id="development">
25             <!-- Transaction manager -->
26             <transactionManager type="JDBC"></transactionManager>
27             <!-- data source -->
28             <dataSource type="pooled">
29                 <property name="driver" value="${jdbc.driver}" />
30                 <property name="url" value="${jdbc.url}" />
31                 <property name="username" value="${jdbc.username}" />
32                 <property name="password" value="${jdbc.password}" />
33             </dataSource>
34         </environment>
35     </environments>
36     <!-- Mapper -->
37     <mappers>
38         <package name="com.chenyanbin.dao" />
39     </mappers>
40 </configuration>

1.3 Plugins interceptor

One of the functions of interceptors is that we can intercept the calls of some methods. We can choose to add some logic before and after the execution of these intercepted methods, or we can execute our own logic when executing these intercepted methods instead of the intercepted methods. One of the original intention of Mybatis interceptor design is for users to realize their own logic at some time without having to move the inherent logic of Mybatis. For example, for the Executor, there are several implementations in Mybatis: BatchExecutor, reuseexecution, simpleexecution, and cachexecution. At this time, if you think the query methods of these implementations for the Executor interface can't meet your requirements, what should you do? Do you want to change the source code? Of course not. We can set up a query method for the Mybatis interceptor to intercept the Executor interface. After intercepting, we can implement our own query method logic, and then we can choose whether to continue to execute the original query method or not.

Mybatis provides us with an Interceptor interface, through which we can define our own interceptors. Let's first look at the definition of this interface:

We can see that there are three methods defined in the interface, intercept, plugin and setProperties. The plugin method is used by the interceptor to encapsulate the target object. Through this method, we can return the target object itself or its agent. When the returned method is an agent, we can intercept the methods to call the intercept method, and of course, we can call other methods, which will be explained later. The setProperties method is used to specify some properties in the Mybatis configuration file.

The most important thing to define your own Interceptor is to implement the plugin method and intercept method. In the plugin method, we can decide whether to intercept and then decide what kind of target object to return. The intercept method is the method to be executed when intercepting.

For the plugin method, mybatis has provided us with an implementation. Mybatis has a class called plugin, which has a static method wrap(Object target,Interceptor interceptor), through which you can decide whether the object to be returned is the target object or the corresponding agent.

There are two important annotations for implementing your own Interceptor. One is @ intercepts, whose value is an array of @ Signature. @Intercepts indicates that the current object is an Interceptor, while @ Signature indicates the interface, method and corresponding parameter type to be intercepted.

 

Create your own Interceptor: MySimpleInterceptor.java

 1 package com.chenyanbin.util;
 2 
 3 import java.util.Properties;
 4 
 5 import org.apache.ibatis.executor.Executor;
 6 import org.apache.ibatis.mapping.MappedStatement;
 7 import org.apache.ibatis.plugin.Interceptor;
 8 import org.apache.ibatis.plugin.Intercepts;
 9 import org.apache.ibatis.plugin.Invocation;
10 import org.apache.ibatis.plugin.Plugin;
11 import org.apache.ibatis.plugin.Signature;
12 import org.apache.ibatis.session.ResultHandler;
13 import org.apache.ibatis.session.RowBounds;
14 
15 @Intercepts({ @Signature(method = "query", type = Executor.class, args = { MappedStatement.class, Object.class,
16         RowBounds.class, ResultHandler.class }) })
17 public class MySimpleInterceptor implements Interceptor {
18     /*
19      * Parameter: Invocation {agent object, monitored method object, actual parameter} is required when the currently monitored method is running.
20      */
21     public Object intercept(Invocation invocation) throws Throwable {
22         // TODO Auto-generated method stub
23         System.out.println("Before the intercepted method is executed, the auxiliary services...");
24         Object object = invocation.proceed(); // Execute blocked method
25         System.out.println("After the intercepted method is executed, the auxiliary service is...");
26         return object;
27     }
28 
29     /*
30      * Parameter: target indicates the intercepted object, which should be the Executor interface instance object function: if the intercepted object's class has an implementation interface, a proxy object will be generated for the current intercepted object.
31      * If the class of the intercepted object does not specify an interface, the subsequent behavior of the object will not be operated by the agent.
32      */
33     public Object plugin(Object target) {
34         // TODO Auto-generated method stub
35         return Plugin.wrap(target, this);
36     }
37 
38     public void setProperties(Properties properties) {
39         // TODO Auto-generated method stub
40 
41     }
42 
43 }

MyBatis core configuration file: myBatis-config.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE configuration
 3   PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 4   "http://mybatis.org/dtd/mybatis-3-config.dtd">
 5 <configuration>
 6     <!-- Attribute configuration -->
 7     <properties resource="config.properties"></properties>
 8     <!-- Alias configuration -->
 9     <typeAliases>
10         <package name="com.chenyanbin.beans" />
11         <package name="com.chenyanbin.dao" />
12     </typeAliases>
13     <!-- ObjectFactory Object factory -->
14     <objectFactory type="com.chenyanbin.util.MyObjectFactory"></objectFactory>
15     <!-- Plugins Interceptor -->
16     <plugins>
17         <plugin interceptor="com.chenyanbin.util.MySimpleInterceptor"></plugin>
18     </plugins>
19     <!-- Type processor -->
20     <!-- <typeHandlers> from java Medium Boolean turn jdbc Medium NUMERIC <typeHandler handler="com.chenyanbin.util.MyTypeHandler" 
21         javaType="Boolean" jdbcType="NUMERIC" /> </typeHandlers> -->
22     <!-- Environmental configuration -->
23     <environments default="development">
24         <!-- Environmental configuration -->
25         <environment id="development">
26             <!-- Transaction manager -->
27             <transactionManager type="JDBC"></transactionManager>
28             <!-- data source -->
29             <dataSource type="pooled">
30                 <property name="driver" value="${jdbc.driver}" />
31                 <property name="url" value="${jdbc.url}" />
32                 <property name="username" value="${jdbc.username}" />
33                 <property name="password" value="${jdbc.password}" />
34             </dataSource>
35         </environment>
36     </environments>
37     <!-- Mapper -->
38     <mappers>
39         <package name="com.chenyanbin.dao" />
40     </mappers>
41 </configuration>

unit testing

 1 package com.chenyanbin.test;
 2 
 3 import java.io.IOException;
 4 import java.io.InputStream;
 5 import java.util.List;
 6 import org.apache.ibatis.io.Resources;
 7 import org.apache.ibatis.plugin.Interceptor;
 8 import org.apache.ibatis.session.SqlSession;
 9 import org.apache.ibatis.session.SqlSessionFactory;
10 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
11 import org.junit.After;
12 import org.junit.Before;
13 import org.junit.Test;
14 import com.chenyanbin.beans.Dept;
15 import com.chenyanbin.dao.DeptMapper;
16 
17 public class TestMain_01 {
18     private SqlSession session;
19 
20     @Before
21     public void Start() {
22         try {
23             InputStream inputStream = Resources.getResourceAsStream("myBatis-config.xml");
24             SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
25             session = factory.openSession();
26         } catch (Exception e) {
27             e.printStackTrace();
28         }
29     }
30 
31     @After
32     public void end() {
33         if (session == null) {
34             session.close();
35         }
36     }
37 
38     @Test
39     public void test01() throws IOException {
40         Dept d2 = new Dept();
41         d2.setDname("Shanghai Business Department");
42         d2.setLoc("Shanghai");
43         d2.setFlag(false);
44         session.insert("deptSave", d2);
45         session.commit();
46         session.close();
47     }
48 
49     @Test
50     public void test02() {    
51         Interceptor ccInterceptor;
52           DeptMapper dao=session.getMapper(DeptMapper.class);
53           List<Dept> deptList=dao.deptFind();
54           System.out.println("ok");         
55     }
56 
57 }

 1 ##define an appender named console
 2 log4j.appender.console=org.apache.log4j.ConsoleAppender
 3 #The Target value is System.out or System.err
 4 log4j.appender.console.Target=System.out
 5 #set the layout type of the apperder
 6 log4j.appender.console.layout=org.apache.log4j.PatternLayout
 7 #set the layout format pattern
 8 log4j.appender.console.layout.ConversionPattern=[%-5p] %m%n
 9 
10 ##define a logger
11 log4j.rootLogger=debug,console
log4j.properties

MyBatis custom interceptor, only four kinds of interfaces can be intercepted.

Chapter 2 Mapper configuration file details of MyBatis framework

2.1 parameter ({parameter name})

The implementation of {} is to set the parameter value to the preprocessing statement in prepareStatement, and {} in sql statement represents a placeholder, that is, a placeholder.

Use {parameter name} to add the content of the parameter to the specified location in the sql statement.

If there is only one parameter in the current sql statement, the parameter name can be defined at will.

However, if the current sql statement has multiple parameters, the parameter name should be associated with the current table [property name of entity class] or [Map set keyword]

When the above SQL statement is called, we can input parameters in the following two ways

Use {} to read the property content of entity class object

Use {} to read the value of the keyword in the map collection

2.2 difference between {} and ${}

In MyBatis, there are two ways to read the contents of parameters into SQL statements, namely

#{parameter name}: entity class object or Map collection read content

${parameter name}: Entity class object or Map collection reads content

 

In order to see the difference between the two methods, you need to see the SQL delivered when MyBatis executes.

You need to use Log4J log to observe

 

Step 1: load Log4j log toolkit to the project

Step 2: add Log4j configuration file to src/main/resources

Next, we can view

Output result

From here we can see the difference between the two:

'{}: prevent SQL injection by precompiling

${}: the SQL injection attack cannot be prevented because of direct assignment.

In most cases, we use {} to read parameter contents. But in some special cases, we still need to use ${} to read parameters.

For example, there are two tables, EMP 2017 and EMP 2018. If you need to specify the table name dynamically in the query statement, you can only use ${}.

<select>

      select *  from emp_${year}

<select>

For example, if you need to specify the sorting field in the query dynamically, you can only use ${}

<select>

       select  *  from dept order by ${name}

</select>

Simply put, ${} can be used where placeholders are not supported in JDBC

2.3 resultMap

In the MyBatis framework, the attribute with the same name is located from the field name in the table to the entity class. If the attribute name of the entity class is inconsistent with the field name in the table, it cannot be automatically mapped. At this time, you can use resultMap to re-establish the correspondence between the entity class and the field name.

 

2.4 Sql tag

First, we have the following two SQL mappings

The tables to be queried and the fields to be queried in the two query mappings are exactly the same, so the < SQL > tags can be used.

select * from dept.

Where this query needs to be used, it is referenced by the < include > tag

Chapter 3: MyBatis dynamic SQL

3.1 what is MyBatis dynamic SQL

Dynamically determine the query condition or SQL statement content that the query statement depends on according to the parameters provided by the user

3.2 dynamic SQL dependency label

if use

 

 choose,when,otherwise

Similar to the switch case default in Java, only one condition takes effect, that is, only the conditions that are met are executed when, and the conditions that are not met are executed otherwise, indicating the default conditions.

 

Use of when

 

set use

The SET word will be added before the condition of successful splicing and the last "," sign will be ignored.

 

trim use

 

Use of foreach

foreach tag is used to traverse the content of the collection, and the content will be part of the SQL statement.

In the actual development process, it is mainly used for the construction of in statements and batch add operations.

The properties of foreach element mainly include item, index, collection, open, separator, close.

Case 1. Using foreach to implement batch adding

Case 2. Use foreach to traverse list set as query condition

Case 3. Using foreach traversal array as query condition

Case 4. Use foreach to traverse Map as query condition

Posted by vahidi on Tue, 15 Oct 2019 17:43:17 -0700