Title: This paper sorted out the relevant content of Mybatis framework, from the beginning of using JDBC to operate the database, to understand the steps that need to be performed at the bottom of the DAO layer, to imitating Mybatis custom framework, to sort out the framework structure of Mybatis. After that, I will introduce the basic use and common features of MyBatis framework, understand the daily application of MyBatis, and finally go deep into the framework source code to feel the exquisite design of MyBatis framework.

  • Note: Article content output source: Pull hook education Java high salary training camp;

Review the JDBC operation process

  1. Load the database connection driver
  2. Get the database connection through the driver management class
  3. Gets the precompiled statement
  4. Sets precompiled statement parameters
  5. Execute the SQL and process the result set
  6. Release resources
public static void main(String[] args) { 
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
	try { 
        // 1. Load the database driver
        Class.forName("com.mysql.jdbc.Driver"); 
        // 2. Access the database connection through the driver management class
        connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis? characterEncoding=utf-8"."root"."root"); 
        
        String sql = "select * from user where username = ?";
        // 3. Get the precompiled statement
        preparedStatement = connection.prepareStatement(sql); 
        // 4. Set precompiled statement parameters
        preparedStatement.setString(1."tom");
        // 5. Execute SQL to process the result set
        resultSet = preparedStatement.executeQuery();
       
        while (resultSet.next()) {
            int id = resultSet.getInt("id");
            String username = resultSet.getString("username");
            
            user.setId(id);
            user.setUsername(username);
        }
        System.out.println(user); 
    } catch (Exception e) { 
        e.printStackTrace();
    } finally { 
        // 6. Release resources
        if(resultSet ! =null) { 
            try {
                resultSet.close();
            } catch(SQLException e) { e.printStackTrace(); }}if(preparedStatement ! =null) { 
            try {
                preparedStatement.close();
            } catch(SQLException e) { e.printStackTrace(); }}if(connection ! =null) { 
            try {
                connection.close();
            } catch(SQLException e) { e.printStackTrace(); }}}}Copy the code

Problems with using JDBC directly:

  1. The frequent creation and destruction of database connections waste system resources.
  2. SQL statements are hardcoded in code, and changes to SQL statements require changes to Java code
  3. There is hard coding in the preparedStatement placeholder parameter
  4. The result set parsing is hard coded (query column names) and the system is not easy to maintain

Problem Solution

  1. The database frequently creates connections and releases resource – wise database connection pools
  2. Hard coding of SQL statements and parameters
  3. Manual parsing encapsulation returns a result set of reflection, introspection

Custom framework design

End of use:

Provide the core configuration file

/** * sqlmapconfig. XML: store data source information, import mapper. XML */
Copy the code

Frame side:

  1. Reading configuration Files

    Javabeans can be created to store */
    public class Configuration {
        / / the data source
        private DataSource dataSource;
        // Map set: key:statementId value:MappedStatement
        private Map<String,MappedStatement> mappedStatementMap = 
            new HashMap<String, MappedStatement>();
    }
    
    public class MappedStatement {
        //id
        private Integer id;
        / / SQL statements
        private String sql;
        // Enter parameters
        privateClass<? > paramterType;// Output parameters
        privateClass<? > resultType; }Copy the code
  2. Parsing configuration files

    Create the SqlSessionFactoryBuilder is class

    Use DOM4J to parse the Configuration file and encapsulate the parsed content in Configuration and MappedStatement

  3. Create a SqlSessionFactory

    Create an implementation class DefaultSqlSession for SqlSessionFactory and implement the openSession() method to obtain the sqlSession interface instance object (pass the Configuration object).

  4. Creating the SqlSession interface and implementing classes encapsulates CRUD methods

    SelectList (String StatementId,Object param

    SelectOne (String StatementId,Object Param) Queries a single Object

    Close () frees resources

    Specific implementation: encapsulation JDBC to complete the database table query operation

    The Executor class, which gets the DataSource, SQL, paramterType, resultType from the Configuration class, sets the precompiled statement placeholder values by reflection, executes SQL, and parses the result into an object by introspection by mapping column names to object attributes

Custom framework optimization

Problems with the above custom framework

  1. Dao implementation class has duplicate code, the entire operation process is repeated (create SqlSession, call SqlSession method, close SqlSession)
  2. The DAO implementation class is hard-coded. When the SqlSession method is called, the Id of Statement is hard-coded

The solution

Use proxy mode to create proxy objects for the interface

Mybatis for quick use

1. Rely on

<! --mybatis-->
<dependency> 
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.5</version>
</dependency>
<! - mysql driver - >
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.6</version>
    <scope>runtime</scope>
</dependency>
Copy the code

2. Create table and entity classes respectively

3. Compile the UserMapper mapping file

<?xml version="1.0" encoding="UTF-8" ? > 
      
<mapper namespace="userMapper">
    <select id="findAll" resultType="com.lagou.domain.User">
        select * from User
    </select>
</mapper>
Copy the code

4. Compile MyBatis core file

<?xml version="1.0" encoding="UTF-8" ? >

      
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///test"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/lagou/mapper/UserMapper.xml"/>
    </mappers>
</configuration>
Copy the code

5. CRUD

Note: Add, delete, or change requires a transaction to be committed or set to automatic commit

Example:

InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
// SqlSession sqlSession = sqlSessionFactory.openSession(true);
// With the argument true to commit the transaction automatically
SqlSession sqlSession = sqlSessionFactory.openSession();
// namespace.id
int insert = sqlSession.insert("userMapper.add", user);
System.out.println(insert);
// Commit the transaction
sqlSession.commit();
sqlSession.close();
Copy the code

MyBatis core profile hierarchy

  • The configuration configuration
    • The properties attribute
    • Settings set
    • TypeAliases Type alias
    • TypeHandlers type handler
    • ObjectFactory objectFactory
    • The plugins plugin
    • Environments environment
      • Environment Environment variables
        • TransactionManager Type: [JDBC, MANAGED]
        • DataSource dataSource type: [UNPOOLED, POOLED, JNDI]
    • DatabaseIdProvider Indicates the vendor id of the database
    • Mappers mapper

mapper.xml

Dynamic SQL statement

The main structure of SQL statements can not be determined in the compilation fashion, only when the program runs, in the process of execution can be determined, this TYPE of SQL is called dynamic SQL.

Common labels:

  • <where>

  • <if>

<select id="findByCondition" parameterType="user" resultType="user"> 
    select * from User
    <where>
        <if test="id! = 0">
            and id=#{id}
        </if>
        <if test="username! =null">
            and username=#{username}
        </if>
    </where>
</select>
Copy the code
  • <foreach>

    Properties:

    • Collection: Represents the collection element to iterate over
      1. Collection ⇒ list
      2. Array ⇒ array
      3. Map tail key
    • Open: indicates the beginning of a statement
    • Close: the end of the statement
    • Item: The name of the variable generated by traversing each element of the collection
    • The separator: separator
<select id="findByIds" parameterType="list" resultType="user">
    <include refid="selectUser"></include>
    <where>
        <foreach collection="array" open="id in(" close=")" item="id" separator=",">
            #{id}
        </foreach>
    </where>
</select>
<! -- List ids = new ArrayList(); ids.add(1); ids.add(2); Map params = new HashMap(); params.put("ids", ids); Params. put("title", "Chinese "); -->
<select id="dynamicForeach3Test" resultType="Blog">
    select * from t_blog where title like "%"#{title}"%" and id in
    <foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>
Copy the code
  • <sql>

  • <include>

Mybatis annotation development

Commonly used annotations

  • @ Insert: new

  • @ Update: Update

  • @ the Delete: Delete

  • @ the Select: query

  • @result: implement Result set encapsulation [

    , < Result >,

    ,
    ]

  • @results: can be used with @result to encapsulate multiple Result sets

  • @ONE: Implement one-to-one result encapsulation

  • @many: Implement one-to-many result set encapsulation

    public interface UserMapper { 
        @Select("select * from user") 
        @Results({ 
            @Result(id = true,property = "id",column = "id"),
            @Result(property = "username",column = "username"),
            @Result(property = "password",column = "password"),
            @Result(property = "birthday",column = "birthday"),
            @Result(property = "roleList",column = "id",javaType = List.class,
                    many = @Many(select ="com.lagou.mapper.RoleMapper.findByUid"))})List<User> findAllUserAndRole(a);
    }
    
    public interface RoleMapper {
        @Select("select * from role r,user_role ur where r.id=ur.role_id and ur.user_id=#{uid}")
        List<Role> findByUid(int uid);
    }
    Copy the code

Mybatis cache

  • Level-1 cache is the SQLSession-level cache stored in the HashMap data structure of the SqlSession object. Caches between different SQLsessions do not affect each other. Level-1 cache is enabled by default

  • Level-2 cache is mapper cache. Level-2 cache must be manually enabled

    Level 1 cache

    • After the commit() operation is executed, level-1 cache in the corresponding sqlSession is cleared

The Map of CacheKey

CacheKey cacheKey = new CacheKey(); 
/ / MappedStatement id
// id: namespace + SQLid
cacheKey.update(ms.getId()); 
// offset 0
cacheKey.update(rowBounds.getOffset()); 
// limit is Integer.MAXVALUE
cacheKey.update(rowBounds.getLimit()); 
// A specific SQL statement
cacheKey.update(boundSql.getSql()); 
// Parameter in SQLcacheKey.update(value); .if(configuration.getEnvironment() ! =null) {
    // environmentId
    cacheKey.update(configuration.getEnvironment().getId());
}
Copy the code

The second level cache

  • Level 2 caching is similar to level 1 caching, but is based on the namespace of mapper files

  • The underlying level 2 cache is still a HashMap structure

  • The commit() operation clears the second-level cache data

1. Enable level-2 cache

  1. Add to global configuration file sqlmapconfig. XML

    <! -- Enable level 2 cache --> 
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    Copy the code
  2. Enable caching in mapper.xml

    <! -- Enable level 2 cache -->
    <! Empty label, default type=PerpetualCache relative path can also be customized by implementing Cache interface -->
    <cache></cache>
    Copy the code
  3. The POJO class implements the serialization interface

    Because tier 2 cache storage medium is not memory, it may be serialized to hard disk

UserCache and flushCache configuration items

  • UserCache: specifies whether to disable level-2 cache. The control granularity is SQL. The default value is true in Statement
  • FlushCache: flushes the cache to prevent dirty reads. The default value is true
  • Using caching is dirty reads if you manually modify the query data in the database table

Level 2 cache integration Redis

  • Objective: To implement distributed cache

1. Rely on

<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-redis</artifactId>
    <version>1.0.0 beta 2 -</version>
</dependency>
Copy the code

2. Configuration file

Mapper.xml

<cache type="org.mybatis.caches.redis.RedisCache" />
Copy the code

3. Redis connection configuration file

redis.host=localhost
redis.port=6379
redis.connectionTimeout=5000
redis.password=
redis.database=0
Copy the code

Note:

The hash structure used by mybatis-redis to store data

key: namespace

field: Cachekey

value: result

Because of serialization and deserialization, the object fetched from the cache the second time is not the same as the previous object

Mybatis plug-in introduction

Mybatis is an excellent ORM framework for a wide range of applications. The framework is highly flexible and provides an easy-to-use plug-in extension mechanism across four major components (Executor, StatementHandler, ParameterHandler, ResultSetHandler). Mybatis operates on the persistence layer with the help of four core objects. MyBatis supports the interception of four core objects by plug-ins. For MyBatis, plug-ins are interceptors, which are used to enhance the functions of core objects. The enhanced functions are essentially realized by means of the underlying dynamic proxy.

MyBatis allows the following interception methods:

  • Executor [update, query, commit, rollback]
  • SQL syntax builder StatementHandler[prepare, parameterize, Batch, update, query]
  • ParameterHandler[gerParameterObject, setParameters]
  • Resultsets handler [handleResultSets, handleOutputParameters, etc.]

Custom plug-in

  1. Create a custom plug-in class to implement the Interceptor interface
  2. Override the Intercept() method
  3. You then annotate the plug-in to specify which interfaces and methods to intercept
  4. Configure the written plug-in class in the MyBatis configuration file

MyBatis executes the process

Design patterns

Design patterns used by MyBatis

Design patterns MyBatis reflect
Builder pattern The SqlSessionFactoryBuilder is, the Environment,
The factory method SqlSessionFactory, TransactionFactory, LogFactory
The singleton pattern ErrorContext, LogFactory
The proxy pattern The core Mybatis implementation, MapperProxy, ConnectionLogger, JDK dynamic proxy, and executor. Loader package uses Cglib or Javassist for lazy loading
Portfolio model SqlNode and each subclass ChooseSqlNode and so on
Template method pattern BaseExecutor and SimpleExecutor, BaseTypeHandler and its subclasses such as IntegerTypeHandler;
Adapter mode For example, the Mybatis interface of Log and its adaptation to JDBC, log4j and other logging frameworks
Decorator pattern For example, the implementation of various decorators in the Cache. decorators subpackage of the Cache package
Iterator pattern For example, the iterator pattern PropertyTokenizer