1 Core concepts of myBatis

1.1 Basic Concepts

MyBatis is an excellent persistence layer framework that supports customized SQL, stored procedures, and advanced mapping. MyBatis avoids almost all of the JDBC code and manual setting of parameters and fetching result sets. MyBatis can use simple XML or annotations to configure and map native types, interfaces, and Java’s Plain Old Java Objects (POJOs) to records in the database.

###1.2 Scope and lifecycle of core objects

A simple example:

  • UserMapper.xml
<? 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.niuh.mybatis.dao.UserMapper">
    <select id="selectUser" resultType="com.niuh.mybatis.dao.User">
    select * from User where id = #{id}
  </select>
</mapper>
Copy the code
  • mybatis-config.xml
<? 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>
    <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: / / 192.168.0.147 niuhDB"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <! --<mapper resource="com/niuh/mybatis/dao/xml/UserMapper.xml"/>-->
        <mapper class="com.niuh.mybatis.dao.UserMapper"></mapper>
    </mappers>
</configuration>
Copy the code

Example:

String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
User result = session.selectOne("com.niuh.mybatis.dao.UserMapper.selectUser", 1);
System.out.println(result.toString());
Copy the code
  • SqlSessionFactoryBuilder

The session factory is used to build a session factory based on the config. XML environment and props, and can be discarded after construction.

  • SqlSessionFactory

Factories used to generate sessions are used for the entire duration of the application, and there is generally no need to construct multiple factory objects

  • SqlSession

Acting on a single session, such as during a WEB request, cannot be used as an object property, nor can it be shared across multiple threads because it is thread-unsafe.

1.3 Interface programming

MyBatis introduces the interface mechanism and binds the interface to the namespace name of mapper. XML. MyBatis can dynamically build instances of the interface according to ASM tools.

Session. GetMapper (Class type) is used to obtain the mapper instance, which is usually applied to the method domain.

2 Global configuration

2.1 attributes

The properties element can load properties from an external properties file through a Resource or URL, or set property properties directly. Reference substitution can then be done in XML with ${attribute name}.

<properties resource="app.properties" url="">
    <property name="jdbc.driver" value="com.oracle.jdbc.Driver"/>
</properties>
Copy the code

Resource = app.properties loaded from the class path url=[file:///G:/git/niuh-mybatis/src/main/resources/app.properties](file:///G:/git/tuling-mybatis/src/main/resources/app .properties) based on url loading

Way to reference attributes:{jdbc.user:root}

2.2 Environment Configuration

A project often needs to be deployed in different environments, such as development environment, test environment, rehearsal environment and production environment. The corresponding parameters of each environment are different. The properties of different environments can be set by environment in myBatis.

<environments default="${default.environment}">
        <environment id="test"> <! --type=JDBC|MANAGED--> <transactionManagertype="JDBC"></transactionManager> <! --type=UNPOOLED|POOLED|JNDI-->
            <dataSource type="UNPOOLED">
                <property name="driver" value="${jdbc.driver}"/>
            </dataSource>
        </environment>
        <environment id="dev">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
            </dataSource>
        </environment>
    </environments>
Copy the code

Through the SqlSessionFactoryBuilder is build (environment) to specify which set environment initialization.

2.3 set up

Set the global parameters of MyBatis and agree the global behavior of MyBatis

<settings> <! <setting name="cacheEnabled" value="true"/ > <! --> <setting name="mapUnderscoreToCamelCase" value="true"/>
<settings>
Copy the code

Example Hump naming on and off: Try turning the mapUnderscoreToCamelCase property on or off to observe Account data queries.

2.4 the alias

In myBatis, Java types are often used, such as javaType in parameterType parameter reference in SQL block javaType result set mapping, which should use Java full path name, can be passed

<typeAliases>
    <typeAlias type="com.niuh.mybatis.dao.Account" alias="account"/>
    <package name="com.niuh.mybatis.dao"  />
</typeAliases>
Copy the code

Tip: Do not set this parameter. Because the commonly used class mybatis has built-in aliases, and custom class Settings are not easy to find, affect reading.

2.5 Type processors

One of the most important tasks of the persistence layer framework is to deal with the mapping of data, converting Java types to JDBC-type parameters, and converting JDBC-type result sets to Java types. In MyBatis, it is implemented through the TypeHandler interface.

As you can see, typeHandler is just two things that set parameters and get results. You can set up custom processors

<typeHandlers>
  <typeHandler handler="org.mybatis.example.ExampleTypeHandler"  />
</typeHandlers>
Copy the code

The scope of processing can be specified in two ways

  • javaType=”long”, jdbcType=”Date”
  • @mappedjdbctypes (JDBC type) @mappedtypes Java types

Example: Convert a timestamp of type long to a date type add an arithmetic definition handler class:

@MappedJdbcTypes(JdbcType.TIMESTAMP) @MappedTypes(Long.class) public class LongTimeHandler extends BaseTypeHandler<Long>  { @Override public voidsetNonNullParameter(PreparedStatement ps, int i, Long parameter, JdbcType jdbcType) throws SQLException {
        ps.setDate(i, new Date(parameter));
    }
 
    @Override
    public Long getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return rs.getDate(columnName).getTime();
    }
 
    @Override
    public Long getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return rs.getDate(columnIndex).getTime();
    }
 
    @Override
    public Long getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        returncs.getDate(columnIndex).getTime(); }}Copy the code

Specify typeHandler in a resultMap:

<resultMap id="account2" type="com.niuh.mybatis.dao.Account">
   <result property="createTimestamp" column="createTimestamp" typeHandler="com.niuh.mybatis.dao.LongTimeHandler"/>
</resultMap>
<select id="selectById2" resultMap="account2">
  select a.*,a.createTime as createTimestamp from account a where id = #{id}
</select>
Copy the code

2.6 Mappers

<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper  url="http://www.xxx.com/xml/BlogMapper.xml"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
 <package name="org.mybatis.builder"/>
</mappers>
Copy the code

Loading mode:

  • Resource loads XML files based on the classPath
  • Url: Loads XML files based on resource location
  • Class: load based on interface
  • Package: Scans all classes in the package and loads them
  • Rules of engagement:
  • The namespace in the Mapper must correspond to the interface name.
  • The.xml file must be in the same level of directory as the interface when loaded through a class or package.

3 mapper file

3.1 SQL Statement Block Statement

In the days of writing DAOs via native JDBC, programmers feared nothing more than concatenating SQL statements, concatenating parameters and Settings to return result sets. Hibernate has made concatenating SQL a thing of the past. With ORM, you don’t need to deal with any SQL at all, but this brings new problems. Inability to write custom SQL results in loss of flexibility and better performance. MyBatis addresses this with mapper mapping SQL. Instead of concatenating SQL in JAVA code, it saves a lot of development time by moving it to mapper file centralization to process SQL.

Elements in Mapper:

  • Cache – The cache configuration for a given namespace.
  • ResultMap – Result set mapping.
  • SQL – reusable block of statements that can be referenced by other statements.
  • Insert – Insert statement
  • Update – Update statement
  • Delete – Deletes a statement
  • Select – A query statement

Select usage and attributes

Example:

<select id="selectById" resultType="com.niuh.mybatis.dao.Account">
  select * from account where id = #{id}
</select>
Copy the code

Properties:

<select
  id="selectById"<! -- The unique identifier of the statement block corresponds to the method name in the interface --> parameterType="User"<! -- Parameter Java type --> resultType="hashmap"<! Return result Java type --> resultMap="userResultMap"<! FlushCache = flushCache="false"<! --true flushes the first and second caches on each call --> useCache="true"<! --true Whether to save to level 2 cache --> timeout="10"
  statementType= PREPARED">
Copy the code

Insert&update & delete usage

Example:

<insert id="addUser" keyColumn="id" keyProperty="id" useGeneratedKeys="true"
        parameterType="com.niuh.mybatis.dao.User">
    insert into  user (name,updateTime,createTime) values (#{name},#{updateTime},#{createTime})
</insert>
Copy the code

Properties:

<insert
  id="addUser"<! -- The unique identifier of the statement block corresponds to the method name in the interface --> parameterType="User"<! -- Parameter Java type --> flushCache="true"<! --true flushes the primary and secondary caches with each call --> statementType="PREPARED"< Execution type > keyProperty=""<! -- Java properties corresponding to the primary key, multiple comma separated --> keyColumn=""<! -- Primary key column, multiple comma separated --> useGeneratedKeys=""<! -- After successful insertion, the value is set back to the original parameter -> timeout="20">
Copy the code

3.2 Parameter Mapping

Parameter mapping reference

Parameter mapping is one of the most powerful features, and bases can be referenced in the following ways

  • Single simple parameter reference: If only one parameter in a method can be referenced by any name
  • Multiple simple parameter references: reference #{arg0} #{arg1} or #{param1},#{param2} by parameter subscript
  • Object attribute reference: directly referenced by object attribute name, nested object through. Number for reference
  • Map key reference:
  • Variable name reference (jdK1.8 support) : Reference by method parameter name, jdK1.8 support, and must be compiled with -parameters command

Add compilation parameters to IDEA

Add build parameters in Maven

Note: One but can be introduced by variable name is not available in support of arg0! Parameters reference related attributes javaType=int, # parameter Java type jdbcType=NUMERIC,# JDBC type typeHandler=MyTypeHandler# Specifies the type processor

Parameter splicing ${}

Parameter references based on # work by passing? Placeholders can be preprocessed for better performance and security (to prevent SQL injection), but some requirements are passed? For example, we need dynamic splicing table structure in some scenarios with separate tables. For example, if the systemlog table is 2018_systemlog,2019_systemlog can pass

Example:

@Select("SELECT * FROM ${table} WHERE id = #{id}")
User selectByTable(String table, int id);
Copy the code

3.3 Result set mapping

ResultSet mapping refers to encapsulating and converting contents in a resultSet into Java objects. In the pure JDBC era, getXXX(columnName) of a resultSet is called to obtain attributes and encapsulate them. It’s a lot of code, it’s a lot of inefficient programming especially if the data model is one to many, or many to many, this kind of encapsulation of code becomes very complicated. Result set mapping is designed to solve this problem by processing the relationship between result sets and JAVA objects in a resultMap.

Automatic mapping of result sets

If resultType= “” is specified in the SELECT, no configuration is required. MyBatis automatically generates an implicit resultMap based on the JAV type and attribute in the resultType to complete the result mapping

resultMap

But sometimes JDBC doesn’t fit perfectly with Java Beans and you need to manually set the resultMap

<resultMap id="account2" type="com.niuh.mybatis.dao.Account">
    <id property="id"/>
    <result property="createTimestamp" column="createTimestamp"
            typeHandler="com.niuh.mybatis.dao.LongTimeHandler"/>
</resultMap>
Copy the code

ResultMap =”account2″ in the SELECT element can reference the map.

Base elements and attributes

  • ID: Unique identifier used in the result set
  • Result: Sets a certain pass field

property: jdbcType: javaType: column: typeHandler:

Nested result mappings

Association example:

<resultMap id="accountAndUser" type="com.niuh.mybatis.dao.Account">
    <id property="id" column="id"/>
    <association property="user" javaType="com.niuh.mybatis.dao.User">
        <id property="id" column="user_id"/>
        <result property="name" column="userName"/>
    </association>
</resultMap>
<select id="selectAccountAndUser" resultMap="accountAndUser">
    SELECT a.*, b.name userName from account a,user b where a.user_id=b.id
</select>
Copy the code

Introducing external Select

<! --> <resultMap ID ="accountAndUser2" type="com.niuh.mybatis.dao.Account">
    <id property="id" column="id"/>
    <association property="user" javaType="com.niuh.mybatis.dao.User" select="selectUser" column="user_id">
    </association>
</resultMap>

<select id="selectUser" resultType="com.niuh.mybatis.dao.User">
    select * from user  where id = #{id}
</select>
Copy the code

A collection of the collection

1. Write the attributes of the collection element directly as the word tag of the collection
<resultMap type="com.niuh.mybatis.dao.User" id="userMap">
    <id property="id" column="uid"/>
    <result property="username" column="username"/>
    <result property="password" column="password"/>
    <collection property="roles" ofType="com.niuh.mybatis.dao.Role">
        <id property="id" column="rid"/>
        <result property="name" column="rname"/>
        <collection property="permissions" ofType="com.niuh.mybatis.dao.Permissions">
            <id property="id" column="pid"/>
            <result property="name" column="pname"/>
       </collection>
   </collection>
</resultMap>
Copy the code

When a User is assigned a Set roles Role, a Set permissions can be assigned to all of the User attributes through a multi-table lookup.

Here is the query statement:

<select id="queryUserName" parameterType="string" resultMap="userMap">
        SELECT u.*,r.*,p.* FROM user u inner join user_role ur on ur.uid=u.uid
        inner join role r on r.rid=ur.rid
        inner join permissions_role pr on pr.rid=r.rid
        inner join permissions p on pr.pid=p.pid
        WHERE username=#{username};
</select>
Copy the code
2, by referring to other mapper query methods in the collection tag
<resultMap id="BaseResultMap" type="com.niuh.mybatis.dao.SysUser" >
        <id column="user_id" property="id" jdbcType="BIGINT" />
        <result column="username" property="username" jdbcType="VARCHAR" />
        <result column="password" property="password" jdbcType="VARCHAR" />
        <collection property="sysRoles" column="user_id"
                    select="com.niuh.mybatis.dao.SysRoleMapper.selectRoleListByUserId">
        </collection>
</resultMap>
Copy the code

SysRoles (selectRoleListByUserId); sysRoles (selectRoleListByUserId);

Here are the query statements: we just need to query SysUser

<select id="findByUsername" resultMap="BaseResultMap">
        SELECT
            us.id as user_id,
            us.username,
            us.password
        FROM t_sys_user us  WHERE us.username = #{username}
</select>
Copy the code

SelectRoleListByUserId = selectRoleListByUserId = selectRoleListByUserId = selectRoleListByUserId

<resultMap id="roleResult" type="com.niuh.mybatis.dao.SysRole">
        <id property="id" column="role_id" jdbcType="BIGINT"/>
        <result property="name" column="name" jdbcType="VARCHAR"/>
        <result property="desc" column="desc" jdbcType="VARCHAR"/>
        <collection property="permissions" column="role_id"
                    select="com.niuh.mybatis.dao.SysPermissionMapper.selectPermissionByRoleId">
        </collection>
    </resultMap>
 
    <select id="selectRoleListByUserId" resultMap="roleResult">
        SELECT
            ro.id as role_id,
            ro.name,
            ro.desc
        FROM  t_sys_user_role ur
         LEFT JOIN t_sys_role  ro
        ON  ur.`role_id` = ro.`id` WHERE ur.user_id = #{userId}
    </select>
Copy the code

Likewise, permissions in sysRoles are the same. Both methods can be implemented. The second method does not require writing overly complex SQL, and the methods in each Mapper can be used independently, making it more applicable.