Mybatis madness lecture notes (incomplete)

1. Introduction

1.1 what is Mybatis

  • MyBatis is an excellent persistence layer framework
  • It supports custom SQL, stored procedures, and advanced mapping.
  • MyBatis eliminates almost all JDBC code and the work of setting parameters and obtaining result sets.
  • MyBatis can configure and map primitive types, interfaces and Java POJO s (Plain Old Java Objects) to records in the database through simple XML or annotations.
  • MyBatis was originally a part of apache Open source project iBatis, 2010 project Migrated from apache software foundation to [Google Code]( https://baike.baidu.com/item/google Code / 2346604) and renamed MyBatis.
  • Moved to in November 2013 Github.

advantage:

  • Easy to learn

  • flexible

  • Decouple sql from program code

  • The separation of sql and code improves maintainability.

  • Provide mapping labels to support the mapping between objects and orm fields in the database

  • Provide object relationship mapping labels to support the establishment and maintenance of object relationships

  • Provide xml tags to support writing dynamic sql.

How to get Mybatis:

  • maven warehouse:

    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.8</version>
    </dependency>
    
    
  • Github:https://github.com/mybatis/mybatis-3

  • Chinese documents: https://mybatis.org/mybatis-3/

1.2 persistence

Data persistence

  • Persistence is the process of transforming program data in persistent state and transient state
  • Memory: loss upon power failure
  • Database (JDBC), io file persistence.

1.3 durable layer

Dao layer, Service layer, Controller layer

  • Code block that completes the persistence work
  • The layer boundary is very obvious.

2. The first Mybatis program

2.1 construction environment

Build database

CREATE DATABASE `mybatis`;

USE `mybatis`;

CREATE TABLE `user`(
  `id` INT(20) NOT NULL PRIMARY KEY,
  `name` VARCHAR(30) DEFAULT NULL,
  `pwd` VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO `user`(`id`,`name`,`pwd`) VALUES(1,'WangTwo ','123456'),(2,'Zhang San','1234567'),
(3,'Li Si','12345678')

Import dependency

 <!--Import dependency-->
    <dependencies>
       <!--mysql drive-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.13</version>
        </dependency>
       <!--Mybatis-->
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.8</version>
        </dependency>
       <!--Junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

Write Mybatis tool class

public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            //Get SqlSessionFactory object
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

2.2 coding

  • Entity class

    public class User {
        private int id;
        private String name;
        private String pwd;
    
        public User() {
        }
    
        public User(int id, String name, String pwd) {
            this.id = id;
            this.name = name;
            this.pwd = pwd;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getPwd() {
            return pwd;
        }
    
        public void setPwd(String pwd) {
            this.pwd = pwd;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", pwd='" + pwd + '\'' +
                    '}';
        }
    }
    
  • Dao interface

    public interface UserDao {
        List<User> getUserList();
    }
    
  • Convert mapopper's configuration file to an interface implemented by DAPER

    <?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">
    <!--namespace=Bind a corresponding Dao/Mapper Interface-->
    <mapper namespace="com.lyd.dao.UserDao">
    <!--select Query statement-->
        <select id="getUserList" resultType="com.lyd.pojo.User">
            select * from mybatis.user
        </select>
    </mapper>
    
  • test

Note:

org.apache.ibatis.binding.BindingException: Type interface com.kuang.dao.UserDao is not known to the MapperRegistry.

What is MapperRegistry?

Register mappers in the core configuration file

  ```xml
  <mappers>
          <mapper resource="com/lyd/dao/UserMapper.xml"/>
      </mappers>
  ```
  • junit test

    public class UserDaoTest {
    
        @Test
        public void test(){
    
            //1. Get SqlSession object
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            //2. Execute SQL
            // Method 1: getMapper
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            List<User> userList = userDao.getUserList();
    
            //Mode 2:
    //        List<User> userList = sqlSession.selectList("com.lyd.dao.UserDao.getUserList");
    
            for (User user : userList) {
                System.out.println(user);
            }
    
            //Close sqlSession
            sqlSession.close();
        }
    
    }
    
  • Possible problems:

  1. The profile is not registered
  2. Binding interface error
  3. . wrong method name
  4. Wrong return type
  5. Maven export resource problem

3.CRUD

1. namespace

The package name in the namespace should be consistent with the package name of Dao/mapper interface

2. select

Select, query statement:

  • id: is the method name in the corresponding namespace
  • resultType: return value of sql statement execution
  • parameterType: parameter type
  1. Write interface

     //Query user by id
       User getUserById(int id);
    
  2. Write the sql statement in the corresponding mapper

    <select id="getUserById" parameterType="int" resultType="com.lyd.pojo.User">
            select * from  mybatis.user where id = #{id}
        </select>
    
  3. test

     @Test
        public void getUserById(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
            User user = mapper.getUserById(1);
            System.out.println(user);
    
            sqlSession.close();
        }
    
        //Add, delete and modify transactions that need to be submitted
        @Test
        public void addUser(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
            int res = mapper.addUser(new User(4, "Xiaofei", "123456"));
            if (res>0){
                System.out.println("Insert successful!");
            }
    
            //Commit transaction
            sqlSession.commit();
            sqlSession.close();
    
        }
    
        @Test
        public void updateUser(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
            int res = mapper.updateUser(new User(4, "Xiao Gang", "123123"));
            if (res>0){
                System.out.println("Modified successfully!");
            }
            sqlSession.commit();
            sqlSession.close();
        }
    
        @Test
        public void deleteUser(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            int res = mapper.deleteUser(4);
            if (res>0){
                System.out.println("Deleted successfully!");
            }
    
            sqlSession.commit();
            sqlSession.close();
        }
    

3. insert

<!--Insert statement-->
    <insert id="addUser" parameterType="com.lyd.pojo.User">
        insert into mybatis.user(id,name ,pwd) values (#{id},#{name},#{pwd});
    </insert>

4. update

<!--Modify user-->
    <update id="updateUser" parameterType="com.lyd.pojo.User">
        update mybatis.user set name = #{name},pwd = #{pwd} where id = #{id};
    </update>

5. delete

<!--delete user-->
    <delete id="deleteUser" parameterType="int">
        delete from mybatis.user where id = #{id};
    </delete>

6. Universal Map

Assuming that there are too many tables, fields or parameters in the entity class or database, we should consider using Map

//Universal Map
   int addUser2(Map<String,Object> map);
<!--transmit map of key value-->
   <insert id="addUser2" parameterType="map">
       insert into mybatis.user (id,name,pwd) values (#{userId},#{userName},#{passWord})
   </insert>
@Test
    public void addUser2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

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

        HashMap<String, Object> map = new HashMap<String, Object>();

        map.put("userId",5);
        map.put("userName","Xiao Zhang");
        map.put("passWord","232323");

        mapper.addUser2(map);

        sqlSession.commit();
        sqlSession.close();
    }

Map passes parameters and directly takes the key from sql [parameterType = "map"]

Pass parameters to the Object and directly get the attribute of the Object in sql [parameterType = "Object"]

If there is only one basic type parameter, you can get it directly in sql

Map or annotation is used for multiple parameters

4. Configuration analysis

1. Core profile

  • mybatis-config.xml

  • Mybatis's configuration file contains settings and properties that deeply affect mybatis's behavior

    configuration

    • properties
    • settings
    • typeAliases
    • typeHandlers
    • objectFactory (object factory)
    • plugins
    • environments
      • Environment (environment variable)
        • Transaction manager
        • dataSource
    • databaseIdProvider (database vendor ID)
    • mappers

2. environments

MyBatis can be configured to adapt to a variety of environments

However, remember that although multiple environments can be configured, only one environment can be selected for each SqlSessionFactory instance.

The default transaction manager of Mybatis is JDBC, and the connection pool is POOLED

3. properties

You can reference the configuration file through the properties property

These properties can be configured externally and can be replaced dynamically. You can configure these properties in a typical Java property file or set [db.properties] in the child element of the properties element

Write a configuration file

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?userSSL=true&useUnicode=true&characterEncoding=UTF-8serverTimezone=UTC
username=root
password=root

Introduce in core configuration file

<!--Import external profile-->
    <properties resource="db.properties">
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </properties>

  • You can import external files directly
  • You can add some attribute configurations
  • If two files have the same field, the external configuration file is preferred

4. Type aliases

  • Type alias sets an abbreviated name for a Java type
  • The meaning of existence is only to reduce the redundancy of class fully qualified names
<!--You can alias an entity class-->
    <typeAliases>
        <typeAlias type="com.lyd.pojo.User" alias="User"/>
    </typeAliases>

You can also specify a package name. MyBatis will search for the required Java beans under the package name

Scan the package of an entity class, and its default alias is the class name of this class, with the first letter in lowercase

<typeAliases>
        <package name="com.lyd.pojo"/>
    </typeAliases>

The first type is rarely used for entity classes. If there are many, the second type is used.

The first one can customize the alias, while the second one cannot. If you have to change it, you need to annotate the entity class

@Alias("user")
public class User {

5. mappers

MapperRegistry: register and bind our Mapper file

Method 1: (recommended)

<mappers>
        <mapper resource="com/lyd/dao/UserMapper.xml"/>
    </mappers>

Method 2: register with class file binding

<mappers>
        <mapper class="com.lyd.dao.UserMapper"/>
    </mappers>

Note:

  • Interface and its Mapper configuration file must have the same name
  • The interface and its Mapper configuration file must be in the same package

Method 3: use scanning package for injection binding

6. Life cycle and scope

Scope and lifecycle categories are critical, because incorrect use can lead to very serious concurrency problems.

SqlSessionFactoryBuilder:

  • Once SqlSessionFactory is created, it is no longer needed
  • local variable

SqlSessionFactory:

  • It can be imagined as: database connection pool
  • Once SqlSessionFactory is created, it should always exist during the operation of the application. There is no reason to discard it or recreate another instance.
  • Therefore, the best scope of SqlSessionFactory is the application scope.
  • The simplest is to use singleton mode or static singleton mode.

SqlSession:

  • A request to connect to the connection pool
  • The instance of SqlSession is not thread safe, so it cannot be shared, so its best scope is the request or method scope.
  • It needs to be closed after use, otherwise it will occupy resources

5. Solve the problem of inconsistency between attribute name and field name

resolvent:

  • Alias

    <select id="getUserById" resultType="com.lyd.pojo.User">
            select id,name,pwd as password from  mybatis.user where id = #{id}
        </select>
    
  • resultMap (result set mapping)

    <!--Result set mapping-->
        <resultMap id="UserMap" type="User">
    <!--column Fields in the database, property Properties in entity classes-->
            <result column="id" property="id"/>
            <result column="name" property="name"/>
            <result column="pwd" property="password"/>
        </resultMap>
        <select id="getUserById" resultMap="UserMap">
            select * from  mybatis.user where id = #{id}
        </select>
    
    

6. Log

6.1 log factory

<settings>
<!--Standard log factory implementation-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

6.2Log4j

What is Log4j

  • Log4j yes Apache By using Log4j, we can control the destination of log information transmission Console , documents GUI Components.
  • You can control the output format of each log.
  • By defining the level of each log information, we can control the log generation process in more detail.
  • Through a configuration file To flexibly configure without modifying the application code.
  1. Import the package of log4j first

    <!-- https://mvnrepository.com/artifact/log4j/log4j -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    
  2. configuration file

    #Output the log information with the level of DEBUG to the two destinations of console and file. The definitions of console and file are in the following code
    log4j.rootLogger=DEBUG,console,file
    
    #Relevant settings of console output
    log4j.appender.console = org.apache.log4j.ConsoleAppender
    log4j.appender.console.Target = System.out
    log4j.appender.console.Threshold=DEBUG
    log4j.appender.console.layout = org.apache.log4j.PatternLayout
    log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
    
    #Relevant settings for file output
    log4j.appender.file = org.apache.log4j.RollingFileAppender
    log4j.appender.file.File=./log/kuang.log
    log4j.appender.file.MaxFileSize=10mb
    log4j.appender.file.Threshold=DEBUG
    log4j.appender.file.layout=org.apache.log4j.PatternLayout
    log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
    
    #Log output level
    log4j.logger.org.mybatis=DEBUG
    log4j.logger.java.sql=DEBUG
    log4j.logger.java.sql.Statement=DEBUG
    log4j.logger.java.sql.ResultSet=DEBUG
    log4j.logger.java.sql.PreparedStatement=DEBUG
    
  3. Configure log4j as the implementation of log

    <settings>
            <setting name="logImpl" value="LOG4J"/>
        </settings>
    
  4. Use of Log4j

    static Logger logger = Logger.getLogger(UserMapperTest.class);
    
        @Test
        public void getUserLike(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
    
            logger.info("Test, enter getUserLike Method success!");
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            User user = mapper.getUserById(1);
            System.out.println(user);
    
            sqlSession.close();
        }
    
        @Test
        public void testLog4j(){
            logger.info("info:Entered testLog4j");
            logger.debug("debug:Entered testLog4j");
            logger.error("error:Entered testLog4j");
        }
    
    

7. Pagination

7.1 using limit paging

effect:

  • Reduce data processing

Paging with Limit

Syntax: select * from user limit startIndex,pageSize;
use: select * from user limit 0,2;

Mybatis paging implementation

  1. Interface

    //paging
       List<User> getUserByLimit(Map<String,Integer> map);
    
  2. Mapper.xml

    <!--paging-->
        <select id="getUserByLimit" parameterType="map" resultMap="UserMap">
            select * from user limit #{startIndex},#{pageSize}
        </select>
    
  3. test

    @Test
        public void getUserByLimit(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
            HashMap<String, Integer> map = new HashMap<String, Integer>();
            map.put("startIndex",0);
            map.put("pageSize",2);
    
            List<User> userList = mapper.getUserByLimit(map);
            for (User user : userList) {
                System.out.println(userList);
            }
    
            sqlSession.close();
    

7.2 rowboundaries paging

Paging is no longer implemented using SQL

  1. Interface

    //Pagination 2
       List<User> getUserByRowBounds();
    
  2. mapper.xml

     <!--Pagination 2-->
        <select id="getUserByRowBounds" resultMap="UserMap">
            select * from user 
        </select>
    
  3. test

    @Test
        public void getUserByRowBounds(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
            //RowBounds implementation
            RowBounds rowBounds = new RowBounds(1, 2);
    
            //Paging through java code level
            List<User> userlist = sqlSession.selectList("com.lyd.dao.UserMapper.getUserByRowBounds", null, rowBounds);
    
            for (User user : userlist) {
                System.out.println(user);
            }
    
            sqlSession.close();
        }
    

8. Development using annotations

8.1 interface oriented programming

  • Everyone has studied object-oriented programming and interface before, but in real development, we often choose interface oriented programming
  • Root cause: decoupling, expandable, improved reuse. In layered development, the upper layer doesn't care about the specific implementation. Everyone abides by common standards, making the development easier and more standardized
  • In an object-oriented system, various functions of the system are completed by many different objects. In this case, how each object implements itself is not so important for system designers;
  • The collaborative relationship between various objects has become the key of system design. From the communication between different classes to the interaction between modules, we should focus on it at the beginning of system design, which is also the main work of system design. Interface oriented programming refers to programming according to this idea.

Understanding of interface

  • From a deeper understanding, the interface should be the separation of definition (specification, constraint) and Implementation (the principle of separation of name and reality).
  • The interface itself reflects the system designer's abstract understanding of the system.
  • There shall be two types of interfaces:
    • The first type is the abstraction of an individual, which can correspond to an abstract class;
    • The second is the abstraction of an aspect of an individual, that is, the formation of an abstract interface;
  • An individual may have multiple Abstract faces. Abstract body and abstract surface are different.

Three oriented differences

  • Object oriented means that when we consider a problem, we take the object as the unit and consider its attributes and methods
  • Process oriented means that when we consider a problem, we consider its implementation in a specific process (transaction process)
  • Interface design and non interface design are aimed at reuse technology, and object-oriented (process) is not a problem It is more reflected in the overall architecture of the system

8.2 development using annotations

  1. Annotation is implemented on the interface

    @Select("select * from user")
       List<User> getUsers();
    
  2. Configuration interface

    <!--Binding interface-->
        <mappers>
            <mapper class="com.lyd.dao.UserMapper"/>
        </mappers>
    
  3. test

    @Test
        public void test(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            List<User> users = mapper.getUsers();
            for (User user : users) {
                System.out.println(user);
            }
            sqlSession.close();
        }
    

8.3 CRUD

Implement automatic transaction submission when the tool class is created

public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession(true);
    }

Write the interface and add comments

public interface UserMapper {

   //query
   @Select("select * from user")
   List<User> getUsers();

   @Select("select * from user where id = #{id}")
   User getUserById(@Param("id") int id);

   //add to
   @Insert("insert into user(id,name,pwd) values(#{id},#{name},#{password})")
   int addUser(User user);

   //modify
   @Update("update user set name = #{name},pwd = #{password} where id = #{id}")
   int updateUser(User user);

   //delete
   @Delete("delete from user where id = #{id}")
   int deleteUser(@Param("id") int id);

}

test

@Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = mapper.getUsers();
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.close();
    }

    @Test
    public void getUserById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        User userById = mapper.getUserById(1);
        System.out.println(userById);

        sqlSession.close();
    }

    @Test
    public void addUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        mapper.addUser(new User(6,"complete","123123"));

        sqlSession.close();
    }

    @Test
    public void updateUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        mapper.updateUser(new User(6,"Wang Wu","1234567"));

        sqlSession.close();
    }

    @Test
    public void deleteUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        mapper.deleteUser(6);

        sqlSession.close();
    }

9. Lombok

Notes:

@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows

explain:

@Data:Nonparametric structure, get,set,toString,hashcode,equals
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
@ToString
@Getter

10. Many to one processing

Many to one understanding:

  • Multiple students correspond to one teacher
  • For students, it is a many to one phenomenon, that is, a teacher is associated with students

Database design

SQL:

CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher(`id`, `name`) VALUES (1, 'Miss Qin');

CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8


INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', 'Xiao Ming', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', 'Xiao Hong', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', 'Xiao Zhang', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', 'petty thief', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', 'Xiao Wang', '1');

Nested processing by query

<!--
Idea:
    1. Query all student information
    2. According to the student's tid,Find the corresponding teacher
-->
    <select id="getStudent" resultMap="StudentTeacher">
        select * from student
    </select>

    <resultMap id="StudentTeacher" type="Student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <!--For complex attributes, we need to deal with objects separately: association  Set: collection-->
        <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
    </resultMap>

    <select id="getTeacher" resultType="Teacher">
        select * from teacher where id = #{id}
    </select>

Nested processing according to results

<!--Nested processing according to results-->
    <select id="getStudent2" resultMap="StudentTeacher2">
        select s.id sid,s.name sname,t.name tname,t.id tid 
        from student s,teacher t
        where s.tid = t.id
    </select>

    <resultMap id="StudentTeacher2" type="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <association property="teacher" javaType="Teacher">
            <result property="name" column="tname"/>
            <result property="id" column="tid"/>
        </association>
    </resultMap>

11. One to many processing

One to many understanding:

  • A teacher has more than one student
  • For teachers, it is a one to many phenomenon, that is, having a group of students (Collection) under a teacher

Entity class

@Data
public class Student {

    private int id;
    private String name;
    private int tid;
}
@Data
public class Teacher {

    private int id;
    private String name;

    //A teacher has more than one student
    public List<Student> students;
}

Nested query by result

<!--Nested query by result-->
    <select id="getTeacher2" resultMap="TeacherStudent">
        select s.id sid,s.name sname,t.name tname,t.id tid
        from student s,teacher t
        where s.tid = t.id and t.id = #{tid}
    </select>

    <resultMap id="TeacherStudent" type="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>

<!--javaType: Specifies the generic information in the type collection of the attribute, which we use ofType obtain-->
        <collection property="students" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

Nested processing by query

<select id="getTeacher1" resultMap="TeacherStudent1">
        select * from teacher where id = #{tid}
    </select>

    <resultMap id="TeacherStudent1" type="Teacher">
        <collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/>
    </resultMap>

    <select id="getStudentByTeacherId" resultType="Student">
        select * from student where tid = #{tid}
    </select>

Summary

  1. association - association [many to one]
  2. Set collection [one to many]
  3. JavaType & ofType
    1. javaType: Specifies the type of the attribute
    2. ofType: used to specify pojo types mapped to lists or collections, and constraint types in generic types

Note:

  • Ensure the readability of SQL and make it easy to understand as much as possible
  • Note the problem of attribute names and fields in one to many and many to one
  • Try to use Log4j to troubleshoot errors

12. Dynamic SQL

What is dynamic SQL: generate different SQL statements according to different conditions

Official website description:
dynamic SQL Element and JSTL Or based on similar XML Similar to our text processor. stay MyBatis In previous versions, there were many elements that took time to understand. MyBatis 3 The element types have been greatly simplified. Now you only need to learn half of the original elements. MyBatis Adopt powerful based OGNL To eliminate most of the other elements.
  -------------------------------
  - if
  - choose (when, otherwise)
  - trim (where, set)
  - foreach

Build environment

CREATE TABLE `blog` (
`id` varchar(50) NOT NULL COMMENT 'Blog id',
`title` varchar(100) NOT NULL COMMENT 'Blog title',
`author` varchar(30) NOT NULL COMMENT 'Blogger',
`create_time` datetime NOT NULL COMMENT 'Creation time',
`views` int(30) NOT NULL COMMENT 'Views'
) ENGINE=InnoDB DEFAULT CHARSET=utf8

if

<select id="queryBlogIf" parameterType="map" resultType="blog">
  select * from blog where 1 = 1
   <if test="title != null">
      and title = #{title}
   </if>
   <if test="author != null">
      and author = #{author}
   </if>
</select>

where

<select id="queryBlogIF" parameterType="map" resultType="blog">
        select * from blog
            <where>
                <if test="title != null">
                    title = #{title}
                </if>
                <if test="author != null">
                    and author = #{author}
                </if>
            </where>

    </select>

set

<update id="updateBlog" parameterType="map">
        update blog
        <set>
            <if test="title != null">
                title = #{title},
            </if>
            <if test="author != null">
                author = #{author}
            </if>
        </set>
        where id = #{id}
    </update>

SQL fragment

  1. Extract common parts using SQL Tags

    <sql id="if-title-author">
            <if test="title != null">
                title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </sql>
    
  2. Use the Include tag reference where necessary

    <select id="queryBlogIF" parameterType="map" resultType="blog">
            select * from blog
                <where>
                   <include refid="if-title-author"></include>
                </where>
        </select>
    

Foreach

<!--
select * from blog where 1 = 1 and (id = 1 or id = 2 or id = 3)
-->
    <select id="queryBlogForeach" parameterType="map" resultType="blog">
        select * from blog
        <where>
            <foreach collection="ids" item="id" open="and (" close=")" separator="or">
                id = #{id}
            </foreach>
        </where>
    </select>

Dynamic SQL is splicing SQL statements. We just need to ensure the correctness of SQL and arrange and combine them according to the format of SQL

13. Cache

13.1 introduction

1. What is Cache?

  • There is temporary data in memory.
  • Put the data frequently queried by users in the cache (memory), and users do not need to query the data from the disk (relational database data file) but from the cache, so as to improve the query efficiency and solve the performance problem of high concurrency system.

2. Why cache?

  • Reduce the number of interactions with the database, reduce system overhead and improve system efficiency.

3. What kind of data can be cached?

  • Data that is frequently queried and not frequently changed.

13.2 Mybatis cache

  • MyBatis includes a very powerful query caching feature, which can easily customize and configure the cache. Caching can greatly improve query efficiency.
  • Two levels of cache are defined by default in MyBatis system: L1 cache and L2 cache
    • By default, only L1 cache is on. (SqlSession level cache, also known as local cache)
    • L2 cache needs to be started and configured manually. It is based on namespace level cache.
    • In order to improve scalability, MyBatis defines the Cache interface Cache. We can customize the L2 Cache by implementing the Cache interface

13.3 L1 cache

L1 cache is also called local cache:

  • The data queried during the same session with the database will be placed in the local cache.
  • In the future, if you need to obtain the same data, you can get it directly from the cache. You don't have to query the database again;

13.4 L2 cache

  • L2 cache is also called global cache. The scope of L1 cache is too low, so L2 cache was born
  • Cache based on namespace level, one namespace corresponds to one L2 cache;
  • Working mechanism
    • When a session queries a piece of data, the data will be placed in the first level cache of the current session;
    • If the current session is closed, the L1 cache corresponding to this session is gone; But what we want is that the session is closed and the data in the L1 cache is saved to the L2 cache;
    • The new session query information can get the content from the L2 cache;
    • The data found by different mapper s will be placed in their corresponding cache (map);

Steps:

  1. Turn on global cache

    <!--Show enable global cache-->
            <setting name="cacheEnabled" value="true"/>
    
  2. Turn on in Mapper where you want to use L2 cache

    <!--At present Mapper.xml Using L2 cache in-->
        <cache/>
    
  3. You can also customize parameters

    <!--At present Mapper.xml Using L2 cache in-->
        <cache eviction="FIFO"
               flushInterval="60000"
               size="512"
               readOnly="true"
        />
    
  4. test

    • All entity classes serialize interfaces first
    @Test
        public void Test2(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            SqlSession sqlSession2 = MybatisUtils.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            User user = mapper.queryUserById(1);
            System.out.println(user);
            sqlSession.close();
    
    
            UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
            User user2 = mapper2.queryUserById(2);
            System.out.println(user2);
            sqlSession2.close();
        }
    

conclusion

  • As long as the L2 cache is enabled, our queries in the same Mapper can get data in the L2 cache
  • The detected data will be put in the first level cache by default
  • Only after the session is committed or closed, the data in the L1 cache will be transferred to the L2 cache

13.5 Ehcache

Ehcache is a widely used java distributed cache, which is used for general cache;

  1. Guide Package

    <!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
            <dependency>
                <groupId>org.mybatis.caches</groupId>
                <artifactId>mybatis-ehcache</artifactId>
                <version>1.2.1</version>
            </dependency>
    
  2. Use the corresponding cache in Mapper

    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
    
  3. Write ehcache XML file

    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
             updateCheck="false">
        <!--
           diskStore: Is the cache path, ehcache There are two levels: memory and disk. This attribute defines the cache location of the disk. The parameters are explained as follows:
           user.home – User home directory
           user.dir – User's current working directory
           java.io.tmpdir – Default temporary file path
         -->
        <diskStore path="./tmpdir/Tmp_EhCache"/>
    
        <defaultCache
                eternal="false"
                maxElementsInMemory="10000"
                overflowToDisk="false"
                diskPersistent="false"
                timeToIdleSeconds="1800"
                timeToLiveSeconds="259200"
                memoryStoreEvictionPolicy="LRU"/>
    
        <cache
                name="cloud_user"
                eternal="false"
                maxElementsInMemory="5000"
                overflowToDisk="false"
                diskPersistent="false"
                timeToIdleSeconds="1800"
                timeToLiveSeconds="1800"
                memoryStoreEvictionPolicy="LRU"/>
        <!--
           defaultCache: Default cache policy, when ehcache This cache policy is used when the defined cache cannot be found. Only one can be defined.
         -->
        <!--
          name:Cache name.
          maxElementsInMemory:Maximum number of caches
          maxElementsOnDisk: Maximum number of hard disk caches.
          eternal:Whether the object is permanently valid, but once it is set, timeout Will not work.
          overflowToDisk:Whether to save to disk when the system crashes
          timeToIdleSeconds:Set the allowed idle time of the object before expiration (unit: seconds). Only if eternal=false It is used when the object is not permanently valid. It is an optional attribute. The default value is 0, that is, the idle time is infinite.
          timeToLiveSeconds:Set the allowable survival time of the object before invalidation (unit: seconds). The maximum time is between creation time and expiration time. Only if eternal=false Used when the object is not permanently valid. The default is 0.,That is, the survival time of the object is infinite.
          diskPersistent: Whether to cache virtual machine restart data Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
          diskSpoolBufferSizeMB: This parameter setting DiskStore(Cache size of disk cache). The default is 30 MB. each Cache Each should have its own buffer.
          diskExpiryThreadIntervalSeconds: The running time interval of disk failure thread is 120 seconds by default.
          memoryStoreEvictionPolicy: When reached maxElementsInMemory When restricted, Ehcache The memory will be cleaned up according to the specified policy. The default policy is LRU(Least recently used). You can set it to FIFO(First in first out) or LFU(Less used).
          clearOnFlush: Whether to clear when the amount of memory is maximum.
          memoryStoreEvictionPolicy:The optional strategies are: LRU(Least recently used, default policy) FIFO(First in first out) LFU(Minimum number of visits).
          FIFO,first in first out,This is the most familiar, first in, first out.
          LFU, Less Frequently Used,This is the strategy used in the above example. To put it bluntly, it has always been the least used. As mentioned above, the cached element has a hit Properties, hit The smallest value will be flushed out of the cache.
          LRU,Least Recently Used,The least recently used element in the cache has a timestamp. When the cache capacity is full and it needs to make room for caching new elements, the element with the farthest timestamp from the current time in the existing cache elements will be cleared out of the cache.
       -->
    
    </ehcache>
    

Keywords: Java Mybatis

Added by Shadow Wolf on Sun, 06 Feb 2022 23:53:52 +0200