First, the overall understanding of architecture mybatis and mybatis

A, myBatis core concepts


Knowledge Point

  1. basic concepts
  2. The core target scope and life cycle
  3. Programming Interface

1, the basic concept

MyBatis is an excellent persistence framework that supports custom SQL, stored procedures and advanced mappings. MyBatis avoids almost all JDBC code and manual setting parameters and obtaining the result set. MyBatis can use simple XML or annotation to configure and map the native information, interfaces and Java POJOs (Plain Ordinary Java Object, ordinary Java Objects) to database records in.

Other persistence solutions: JDBC, DBUtils, JdbcTemplate, Hibernate

2, the core object scope and life cycle

1) Create a database table: user

CREATE TABLE `user` (
  `id` tinyint(4) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
复制代码

2) New pojo entity classes: User

public class User implements Serializable {

    private static final long serialVersionUID = -6611101295813775324L;

    private Integer id;
    private String name;
    private Date createTime;
    private Long updateTime;

    //省略setter、getter方法
}
复制代码

3) Configure the database connection properties: jdbc.properties

jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
jdbc.username=root
jdbc.password=root
default.environment=dev
复制代码

4) Configuration mybatis profile: 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>

    <properties resource="jdbc.properties"></properties>

    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <environments default="${default.environment}">
        <environment id="dev">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driverClassName}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers
        <mapper resource="mapper/UserMapper.xml"></mapper>
    </mappers>
</configuration>
复制代码

5) Custom Processor Type: CustomHandler

@MappedJdbcTypes(JdbcType.TIMESTAMP)
@MappedTypes(Long.class)
public class CustomHandler extends BaseTypeHandler<Long> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Long parameter, JdbcType jdbcType) throws SQLException {
        //ps.setDate(i,new Date(parameter));
        ps.setTimestamp(i,new Timestamp(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 {
        return cs.getDate(columnIndex).getTime();
    }
}
复制代码

6) mapper.xml configuration file: 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.cyan.mapper.UserMapper">
    <resultMap id="baseResultMap" type="com.cyan.pojo.User">
        <id property="id" column="id" jdbcType="INTEGER"></id>
        <result property="name" column="name" jdbcType="VARCHAR"></result>
        <result property="createTime" column="create_time" jdbcType="TIMESTAMP"></result>
        <result property="updateTime" column="update_time" jdbcType="TIMESTAMP" typeHandler="com.cyan.handler.CustomHandler"></result>
    </resultMap>

    <select id="selectUserById" parameterType="java.lang.Integer" resultMap="baseResultMap">
        select * from user where id = #{id}
    </select>
</mapper>
复制代码

7) Write test cases: UserTest

public class UserTest {

    private SqlSession session;

    @Before
    public void init()throws IOException{
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        session = sqlSessionFactory.openSession(true);
    }

    @Test
    public void test01() throws IOException {
        User result = session.selectOne("com.cyan.mapper.UserMapper.selectUserById", 1);
        System.out.println(result.toString());
    }
}
复制代码

SqlSessionFactoryBuilder: plant used to construct a session, based mybatis-config.xml the environment, props factory building session, constructed to be disposable after completion.

SqlSessionFactory: plant used to generate the session, acting during operation of the entire application, generally no need to construct a plurality of objects plant

SqlSession: During acting on a single session, such as a WEB request, can not be used in an attribute of the image can not be shared between multiple threads, because it is thread safe.

3, programming interfaces

Because all went to each call for applications statement and assembly parameters, using the not particularly friendly

myBatis interface mechanism is introduced, the interface mapper.xml the namespace name binding, MyBatis instance of the interface can be dynamically constructed according to ASM tool.

1) create mapper interfaces: UserMapper

User selectUser(Integer id);
复制代码

2) mapper.xml configuration file: UserMapper.xml

<select id="selectUser" resultType="com.tuling.ssm.pojo.User">
    select * from user where id = #{id}
</select>
复制代码

3) Write test cases: UserTest

UserMapper $proxy = session.getMapper(UserMapper.class);
User user = $proxy.selectUserById(2);
System.out.println(user.toString());
复制代码

Second, the global configuration configuration


Knowledge Point

  1. properties properties
  2. environments Properties
  3. attribute settings
  4. typeAliases property
  5. typeHandlers property
  6. mapper mappers

1, properties properties

properties element properties can load external resource file attributes or url, property attribute may be provided directly. Then in xml can be replaced by a reference property name $ {}.

<properties resource="jdbc.properties"></properties>
复制代码

Way reference properties

${jdbc.driverClassName}
# MyBatis3.4.2开始,支持指定默认值
${jdbc.driverClassName:com.mysql.jdbc.Driver}
复制代码

2, environments Properties

A project frequently requires properties such as developing a bad environment, test environment, pre-on-line environment, the production medium in different environments deployment, each parameter setting corresponding to is not the same, is that MyBatis may be disposed in different environments by the environment's.

# 指定应用环境
default.environment=dev
复制代码
<environments default="${default.environment}">
    <environment id="dev">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="${jdbc.driverClassName}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </dataSource>
    </environment>
    <environment id="test">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="${jdbc.driverClassName}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </dataSource>
    </environment>
</environments>
复制代码

3, settings Properties

MyBatis set global parameters, agreed global behavior of myBatis

<settings>
    <setting name="cacheEnabled" value="true"/>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
复制代码

4, typeAliases property

Often used in the java myBatis the type, such as block sql javaType parameter set, the result set map javaType the like, have to use a full path name java, may be provided by an alias attribute typeAliases

<typeAliases>
    <!--<typeAlias type="com.cyan.pojo.User" alias="User"></typeAlias>-->
    <package name="com.cyan.pojo"></package>
</typeAliases>
复制代码

5, typeHandlers property

Persistence framework is one of the more important work mapping data conversion process, converted into a java type jdbc type parameters, and the need to convert the result of integration type jdbc java type. It is achieved by TypeHandler interface mybatis in.

Custom type processor

public class CustomHandler extends BaseTypeHandler<Long> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Long parameter, JdbcType jdbcType) throws SQLException {
        //ps.setDate(i,new Date(parameter));
        ps.setTimestamp(i,new Timestamp(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 {
        return cs.getDate(columnIndex).getTime();
    }
}
复制代码

Profiles way applications

<typeHandlers>
    <typeHandler handler="com.cyan.handler.CustomHandler"
                 javaType="long" jdbcType="TIMESTAMP" />
</typeHandlers>
复制代码

Notes application mode

@MappedJdbcTypes(JdbcType.TIMESTAMP)
@MappedTypes(Long.class)
public class CustomHandler extends BaseTypeHandler<Long> {}
复制代码

6, mappers mapper

<mappers>
    <mapper resource="mapper/UserMapper.xml"></mapper>
    <mapper resource="mapper/AccountMapper.xml"></mapper>
    <!-- mapper与对应的xml文件必须在一个包下 -->
    <!--<mapper class="com.cyan.mapper.UserMapper"/>-->
    <!--<package name="com.cyan.mapper"/>-->
</mappers>
复制代码

resource: Based classpath load xml file

class: Load-based interface

package: Package scan all class, then loading

Rules of engagement :

1) mapper namespace must correspond to the corresponding interface name

2) when loaded by class or package, xml file must be in the same directory level interface

Three, mapper mapping file


Knowledge Point

  1. sql statement block statement
  2. Parameter Mapping
  3. Result set mapping

1. sql statement block statement

1) Mapper is a common element

resultMap – 结果集映射
select – 查询语句
insert – 插入语句
cache – 对给定命名空间的缓存配置
parameterMap - 参数集映射
update – 更新语句
delete – 删除语句
cache-ref - 指定缓存命名空间
sql – 可被其他语句引用的可重用语句块。
复制代码

2) select the common property

id - 语句块的唯一标识,与接口中方法名称对应
parameterMap - 参数集映射
parameterType - 参数java类型
resultMap - 返回结果映射
resultType - 返回结果java类型
statementType - 预处理类型 
timeout - 超时时间
flushCache - 每次调用都会刷新一二级缓存
useCache - 是否保存至二级缓存当中去
复制代码

3) insert & update & delete attributes in common

id - 语句块的唯一标识,与接口中方法名称对应
parameterMap - 参数集映射
parameterType - 参数java类型
statementType - 预处理类型
timeout - 超时时间
flushCache- true每次调用都会刷新一二级缓存

# insert、update还具有如下三个属性(delete则没有)
keyProperty - 主键对应的java属性,多个用 逗号分割
keyColumn - 主键列,多个用逗号分割
useGeneratedKeys - 插入成功后可以获取到数据库自动生成的主键值
复制代码

2, parameter mapping

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

1) simple single reference parameter : if the method is only one parameter can be performed by any reference name

User selectUserById(Integer id);

<select id="selectUserById" parameterType="java.lang.Integer" resultMap="baseResultMap">
    select * from user where id = #{id}
</select>
复制代码

2) a plurality of reference parameters is simple : # {param1} referenced by the index parameter, # {param2}

Integer insertUser(String name, Date createTime, Date updateTime);

<insert id="insertUser">
    insert into user(name,create_time,update_time) values (#{param1},#{param2},#{param3})
</insert>
复制代码

3) Object attribute references : directly referenced by object attribute names, nested objects by reference.

Integer saveUser(User user);

<insert id="saveUser" parameterType="com.cyan.pojo.User"
        keyColumn="id" keyProperty="id" useGeneratedKeys="true">
    insert into user(name,create_time,update_time) values (#{name},#{createTime},#{updateTime,typeHandler=com.cyan.handler.CustomHandler})
</insert>
复制代码

4) map key reference value

<update id="updateUserById" parameterType="java.util.Map">
    update user set name = #{name},update_time = #{updateTime} where id = #{id}
</update>
复制代码

5) variable name referenced

Integer modifyUserById(@Param("id") Integer id,@Param("name") String name,@Param("updateTime")Date updateTime);

<update id="modifyUserById">
    update user set name = #{name},update_time = #{updateTime} where id = #{id}
</update>
复制代码

6) Parameters stitching

Based on a reference parameter #, and its principle is? Placeholder pretreatment can get better performance and security (to prevent SQL injection), but some demand is by? Placeholder can not be achieved, such as in some sub-sub-library scene of the table we need to splice table structure dynamic. For example, a system log table is an annual cut of 2018_systemlog, 2019_systemlog then you can be by the following statement

@Select("select * from ${year}_user where id = #{id}")
User selectUserTableByYear(String year, Integer id);
复制代码

3, the result set mapping

1) result set automatic mapping

在select中指定resultType=""后无需要任何配置 myBatis会基于resultType中的java类型及属性自动推断生成一个隐示的resultMap,从而完成结果映射
复制代码

2)resultMap

Sometimes jdbc and java Bean is not completely fit then you need to manually set resultMap

<resultMap id="baseResultMap" type="com.cyan.pojo.User">
    <id property="id" column="id" jdbcType="INTEGER"></id>
    <result property="name" column="name" jdbcType="VARCHAR"></result>
    <result property="createTime" column="create_time" jdbcType="TIMESTAMP"></result>
    <result property="updateTime" column="update_time" jdbcType="TIMESTAMP" typeHandler="com.cyan.handler.CustomHandler"></result>
</resultMap>

<select id="selectUserById" parameterType="java.lang.Integer" resultMap="baseResultMap">
    select * from user where id = #{id}
</select>

ID:用于结果集中的唯一标识
result:设置一个某通过字段
property:java属性名
jdbcType:jdbc类型
javaType:java类型
column:数据库列名
typeHandler:类型处理器
复制代码

3) nested result mappings (one to one)

Create a relational database:

CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `money` int(11) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
复制代码

AccountMapper.xml:

<resultMap id="accountAndUserResultMap" type="com.cyan.pojo.Account">
    <id property="id" column="id"/>
    <association property="user" javaType="com.cyan.pojo.User">
        <id property="id" column="user_id"/>
        <result property="name" column="userName"/>
    </association>
</resultMap>

<select id="getAccountList" resultMap="accountAndUserResultMap">
    SELECT a.*, u.name userName from account a,user u where a.user_id=u.id
</select>
复制代码

4) the introduction of external select (one)

AccountMapper.xml:

<resultMap id="accountAmpUserResultMap" type="com.cyan.pojo.Account">
    <id property="id" column="id"/>
    <association property="user" javaType="com.cyan.pojo.User"
                 select="com.cyan.mapper.UserMapper.selectUserById" column="user_id">
    </association>
</resultMap>

<select id="selectAccountList" resultMap="accountAmpUserResultMap">
    SELECT a.*, u.name userName from account a,user u where a.user_id=u.id
</select>
复制代码

5) Nesting mapping results (1 to many)

Create a relational database:

CREATE TABLE teacher(
    t_id INT PRIMARY KEY AUTO_INCREMENT,
    t_name VARCHAR(20)
);
INSERT INTO teacher(t_name) VALUES('LS1');
INSERT INTO teacher(t_name) VALUES('LS2');

CREATE TABLE class(
    c_id INT PRIMARY KEY AUTO_INCREMENT,
    c_name VARCHAR(20),
    teacher_id INT
);
ALTER TABLE class ADD CONSTRAINT fk_teacher_id FOREIGN KEY (teacher_id) REFERENCES teacher(t_id);
INSERT INTO class(c_name, teacher_id) VALUES('bj_a', 1);
INSERT INTO class(c_name, teacher_id) VALUES('bj_b', 2);

CREATE TABLE student(
    s_id INT PRIMARY KEY AUTO_INCREMENT,
    s_name VARCHAR(20),
    class_id INT
);
INSERT INTO student(s_name, class_id) VALUES('xs_A', 1);
INSERT INTO student(s_name, class_id) VALUES('xs_B', 1);
INSERT INTO student(s_name, class_id) VALUES('xs_C', 1);
INSERT INTO student(s_name, class_id) VALUES('xs_D', 2);
INSERT INTO student(s_name, class_id) VALUES('xs_E', 2);
INSERT INTO student(s_name, class_id) VALUES('xs_F', 2);
复制代码

ClassesMapper.xml:

<!-- 根据 classId 查询对应的班级信息,包括学生,老师 -->
<!-- 方式一:嵌套结果(使用嵌套结果映射来处理重复的联合结果的子集) -->
<resultMap id="baseResultMap1" type="com.cyan.pojo.Classes">
    <id property="id" column="c_id" />
    <id property="name" column="c_name" />
    <association property="teacher" column="teacher_id" javaType="com.cyan.pojo.Teacher">
        <id property="id" column="t_id" />
        <result property="name" column="t_name" />
    </association>
    <collection property="students" column="c_id" ofType="com.cyan.pojo.Student">
        <id property="id" column="s_id" />
        <result property="name" column="s_name" />
    </collection>
</resultMap>

<select id="getClassesById" parameterType="int" resultMap="baseResultMap1">
    select * from class c,teacher t, student s
    where c.teacher_id = t.t_id
    and c.c_id = s.class_id
    and c.c_id = #{id}
</select>
复制代码

6) the introduction of external select (many)

ClassesMapper.xml:

<!-- 根据 classId 查询对应的班级信息,包括学生,老师 -->
<!-- 方式二:嵌套查询(通过执行另外一个SQL映射语句来返回预期的复杂类型) -->
<resultMap id="baseResultMap2" type="com.cyan.pojo.Classes">
    <id property="id" column="c_id" />
    <id property="name" column="c_name" />
    <association property="teacher" column="teacher_id" javaType="com.cyan.pojo.Teacher"
        select="com.cyan.mapper.TeacherMapper.getTeacherById" />
    <collection property="students" column="c_id" ofType="com.cyan.pojo.Student"
        select="com.cyan.mapper.StudentMapper.getStudentById"/>
</resultMap>

<select id="findClassesById" parameterType="int" resultMap="baseResultMap2">
    select * from class where c_id = #{id}
</select>
复制代码

TeacherMapper.xml:

<resultMap id="baseResultMap" type="com.cyan.pojo.Teacher">
    <id property="id" column="t_id" />
    <result property="name" column="t_name" />
</resultMap>

<select id="getTeacherById" resultMap="baseResultMap" parameterType="int">
    select * from teacher where t_id = #{id}
</select>
复制代码

StudentMapper.xml:

<resultMap id="baseResultMap" type="com.cyan.pojo.Student">
    <id property="id" column="s_id" />
    <result property="name" column="s_name" />
</resultMap>

<select id="getStudentById" resultMap="baseResultMap" parameterType="int">
    select * from student where class_id = #{id}
</select>
复制代码

Guess you like

Origin juejin.im/post/5da28474e51d4577e86d0daf