Mybatis Learn Notes

Mybatis Learn Notes

I. Understanding Mybatis

  • MyBatis is an excellent persistence framework.

  • It supports custom SQL, stored procedures, and advanced mappings.

  • MyBatis eliminates almost all JDBC code and setting parameters and getting result sets.

  • MyBatis can configure and map raw types, interfaces, and Java POJO s (Plain Old Java Objects, plain old Java objects) as records in the database through simple XML or annotations.

  • MyBatis was originally an open source project for apache, iBatis, which was migrated to google code by apache software foundation in 2010 and renamed MyBatis. Migrated to Github in November 2013.

  • The term iBATIS, derived from the combination of ** "internet" and "abatis", is a persistent Java-based framework**. IBATIS provides a persistence layer framework that includes SQL Maps and Data Access Objects (DAOs)

Second, the first mybatis program

1. Import the corresponding jar package

Import mybatis packages and database driver packages

Corresponding maven dependencies:

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.25</version>
</dependency>

Import unit test class junit

<dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
        <scope>test</scope>
</dependency>

2. Write mybatis core configuration file

<?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">
          <!--There value Fill in the corresponding JDBC Four piece suit 
			com.mysql.cj.jdbc.Driver yes mysql 8.0 In the above version,
			5.0 Of com.mysql.jdbc.Driver-->
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <!--Notice here&Symbols need to be used&amp;replace-->
        <property name="url" value="jdbc:mysql://localhost:3306/mytestdatabase?useSSL=true&amp;useUnicode=true&amp;character=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
      </dataSource>
    </environment>
  </environments>
    <mappers>
<!--Notice here mappers Label, which will be used for registration later mapper file-->
    </mappers>
</configuration>

3. Write entity classes and dao/Mapper interfaces

Entity classes (methods of entity classes are omitted here and need to be written when used):

Note that the attributes of the entity class must match the field names in the database

package com.li.pojo;

public class User {
    private int id;
    private String password;
    private String name;

}

dao/Mapper interface

package com.li.dao;

import com.li.pojo.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;
import java.util.Map;

public interface UserMapper {
    //User Class Common Methods
    //Query all users
    public List<User> getUserList();
    //Query users by id
    public User selectUserById(int id);
    //Query users by name
    public List<User> selectUserByName(Map<String,Object> map);
    public int addUser(User user);
    public int updateUser(User user);
    //If the @Param() comment is used, the naming in the comment takes precedence in sql, and if the parameter has only one basic type, it can be omitted
    // If there are multiple parameters, the comment is required before each parameter
    public int deleteUser(@Param("id") int id);
}

4. Write mapper.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">
<!-- Namespace namespace Fill in the package path for the corresponding mapping interface-->
<mapper namespace="com.li.dao.UserMapper">
    <!--  id Equivalent to method name, resultType Fully qualified name is required for query result type(package path) 
			parameterType Basic types for parameter types can be omitted-->
    <select id="getUserList" resultMap="com.li.pojo.User">
        select * from t_user
    </select>
    <select id = "selectUserById" parameterType="int" resultType = "com.li.pojo.User">
        <!--Use#{} or ${} to get properties in the corresponding method
			-->
        select * from t_user where id = #{id}
    </select>
    <select id = "selectUserByName" parameterType="map" resultType = "com.li.pojo.User">
        select * from t_user where name = #{name}
    </select>
    <insert id = "addUser" parameterType= "com.li.pojo.User">
        insert into t_user(id,password,name) value (#{id},#{password},#{name})
    </insert>
    <update id = "updateUser" parameterType = "com.li.pojo.User">
        update t_user set name = #{name} ,password = #{password} where id = #{id}
    </update>
</mapper>

Note: Methods in the dao interface need to be registered here, otherwise they cannot be used

Regarding areas using #{} and ${}:

  • #{} executes SQL in a precompiled way to prevent SQL injection
  • However, ${} executes SQL using normal classes and cannot prevent SQL injection

About namespaces:

** Naming Resolution: ** To reduce the amount of input, MyBatis uses the following naming resolution rules for all configuration elements with names, including statements, result maps, caches, and so on.

  • Fully qualified names such as "com.mypackage.MyMapper.selectAllThings" will be used directly for lookup and use.
  • Short names (such as "selectAllThings") can also be used as a separate reference if they are globally unique. If it is not unique, there are two or more identical names (such as "com.foo.selectAllThings" and "com.bar.selectAllThings"), then a "short name is not unique" error will occur and a fully qualified name must be used in this case.

5. Register mapper file in configuration file

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

6. Write a tool class to get SqlSession

package com.li.util;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class MybatisUtil {
    //Privateize SqlSessionFactory object
    private static SqlSessionFactory sqlSessionFactory;
    static{
        //mybatis core profile path
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            //read file
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //Instantiate SqlSessionFactory object through mybatis core configuration file
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }
    public static SqlSession getSqlSession(){
        //Create Sqlsession object from SqlSession factory object
         //Here you can configure whether to automatically submit openSession(boolean autoCommit)
		return sqlSessionFactory.openSession();
    }
}

7. Use

package com.li.dao;

import com.li.pojo.User;
import com.li.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class UserMapperTest {
    @Test
    public void selectTest1(){
        //The first step is to get the SqlSession object
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtil.getSqlSession();
        //Execute SQL
            //Mode 1:
          //The underlying principle of mybatis development is java reflection
            //The getMapper() method returns the Object object by default, with the dao interface class object to be obtained as a parameter, which needs to be overridden if not written
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            List<User> users= userMapper.getUserList();
            //Mode 2: (not recommended)
            //Direct positioning of parameters to methods
            //List<User>users = sqlSession.selectList("com.li.dao.UserMapper.getUserList");
            for (User user : users) {
                System.out.println(user);
            }
        }finally {
            //Close sqlSession
            //It is recommended to close using try{}finally{}
            sqlSession.close();
        }
    }
    @Test
    public void insertTest(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        userMapper.addUser(new User(4,"123123","Ahha"));
        //Note that additions and deletions need to be submitted
        sqlSession.commit();
        sqlSession.close();
    }
    @Test
    public void updateTest(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        userMapper.updateUser(new User(4,"123321","Big Fertilizer"));
        //Note that additions and deletions need to be submitted
        sqlSession.commit();
        sqlSession.close();
    }
    @Test
    public void deleteTest(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        userMapper.deleteUser(4);
        sqlSession.commit();
        sqlSession.close();
    }
}

Three, Map and Fuzzy Query

1. Map as a parameter

Methods in the dao interface:

public List<User> selectUserByName(Map<String,Object> map);

In mapper. In the XML file:

    <select id = "selectUserByName" parameterType="map" resultType = "com.li.pojp.User">
        <!--When the parameter type is map When using the#{}Pass key to get the corresponding value in the map collection-->
        select * from t_user where name = #{name}
    </select>

2. Fuzzy Query

Methods in dao interface

  public List<User> selectUserByLike(String name);

Mode 1: String splicing when passing values

mapper.xml file

    <select id="selectUserByLike" resultMap="UserMap">
        <!--Attention is to use ${}Value taking, not available#{}-->
        select * from t_user where name like '%${name}%'
        <!--You can stitch here or you can stitch when you pass parameters, either way you can SQL injection-->
    </select>

Mode 2: Splicing using concat() SQL function, which can effectively prevent SQL injection problems

mapper.xml file

    <select id="selectUserByLike" resultMap="UserMap">
		select * from t_user where name like concat('%',#{bookName},'%')
    </select>

Test:

    @Test
    public void selectTest4(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = userMapper.selectUserByLike("plum");
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.close();
    }

4. mybatis configuration instructions

1. Use of common configuration properties

Configuration (configuration)

  • properties
  • settings
  • typeAliases (type alias)
  • environments (environment configuration)
    • Environment (environment variable)
      • transactionManager (Transaction Manager)
      • dataSource (data source)
  • mappers

Note: The order of labels in the mybatis configuration file is specified in the following order:

properties - > Settings - > typeAliases - > environments - > mappers

1.properties

    <!--Use resource Properties are imported into an external database configuration file, which can then be used in the configuration file ${name}How to get the data you need-->
<properties resource="db.properties"/>

<properties>
        <!--        You can customize the properties here,Be similar to java Global variable, which takes precedence over external resource attributes if it has the same name as an external resource-->
        <!-- for example   <property name="username" value="root"/>-->
</properties>

2.environments (environment configuration)

    <!--    Default Use development Environmental Science,Use a different environment to use here default Property Application Corresponding Environment id-->
    <environments default="development">
		<!--You can configure multiple environments here-->
       <!--Environment 1:--> 
        <environment id="development">
            <!--            Default Use JDBC Manager, or you can use MANAGED Manager-->
            <transactionManager type="JDBC"/>
            <!--Data Source Configuration Usage type Properties can apply to different data sources 
			Common data sources are dbcp c3p0 druid The purpose of the data source is to connect to the database, which is different in efficiency and some functions-->
            <!--  Data source default open pool connection Other properties are UNPOOLED: Do not use pooling Technology JNDI: Normal Connection-->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
         <!--Environment 2-->
        <environment id="test">
            <!--            Default Use JDBC Manager-->
            <transactionManager type="MANAGED">
                <perperty name ="closeConnection" value = "false"/>
             </transactionManager>
            <!--            Data source opens pool connection by default-->
            <dataSource type="UNPOOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

Transaction Manager Description

3.typeAliases (type alias)

    <!--Use typeAliases Labels can be given to java Alias type-->
<typeAliases>
        <!--        Mode 1: Custom type-->
    	        <!-- type Attribute is java The fully qualified name of the class, alias Property is given to java Alias from Class -->
        <!--        <typeAlias type="com.li.pojo.User" alias="user"/>-->
        <!--        Mode 2: Use package scanning to import custom types with aliases in lowercase initials-->
        <package name="com.li.pojo"/>
</typeAliases>

Once aliased, it can be used in mapper files

    <!--For example:-->
<select id = "selectUserById" parameterType="int" resultType = "user">
        select * from t_user where id = #{id}
</select>

Below are some built-in type aliases for common Java types. They are case-insensitive, and note that special naming styles have been adopted to cope with duplicate naming of the original type.

aliasType of mapping
_bytebyte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
objectObject
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator

4.settings (settings)

These are extremely important adjustment settings in MyBatis that change the runtime behavior of MyBatis. Its properties include the meaning of the settings, default values, and so on.

And what we commonly use is

Set NamedescribeValid ValueDefault value
cacheEnabledTurn on or off any caches configured in all mapper profiles globally.true | falsetrue
autoMappingBehaviorSpecify how MyBatis should automatically map columns to fields or attributes. NONE means to turn off automatic mapping; PARTIAL will only automatically map fields that do not define nested result mappings. FULL automatically maps any complex result set, whether nested or not.NONE, PARTIAL, FULLPARTIAL
safeRowBoundsEnabledWhether paging is allowed in nested statements. Set to false if allowed.true | falseFalse
mapUnderscoreToCamelCaseWhether to turn on automatic mapping of hump naming, i.e. column name A_from a classic database COLUMN maps to the classic Java property name aColumn.true | falseFalse
localCacheScopeMyBatis uses a Local Cache mechanism to prevent circular references and speed up duplicate nested queries. The default value is SESSION, which caches all queries executed in a session. If the value is STATEMENT, the Local Cache will only be used to execute statements, and different queries for the same SqlSession will not be cached.SESSION | STATEMENTSESSION
returnInstanceForEmptyRowMyBatis returns null by default when all columns returning rows are empty. When this setting is turned on, MyBatis returns an empty instance. Note that it also applies to nested result sets, such as collections or associations. (New at 3.4.2)true | falsefalse
logPrefixSpecify the prefix MyBatis adds to the log name.Any stringNot set
logImplSpecify the specific implementation of the log used by MyBatis, which will be automatically searched if not specified.SLF4J | LOG4J(deprecated since 3.5.9) | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGINGNot set

Even though there are so many optional settings, we tend to use only a few of them, such as

        <settings>
<!--            Turn on hump naming mapping-->
            <setting name="mapUnderscoreToCamelCase" value="true"/>
<!--            Setup Use JDK Standard log factories:-->
       		<setting name="logImpl" value="STDOUT_LOGGING"/>
            <!--Displayed declarations use caching-->
         	<setting name="cacheEnable" value="true"/>
        </settings>

5.mappers (mappers)

The mappers tag in the mybatis configuration file is used to register the mapper interface for the dao layer

    <mappers>
        <!--        Mode 1: Use the way resources are referenced-->
        <mapper resource="com/li/dao/StudentMapper.xml"/>
        <!--        Mode 2: Use interface name, Mapper.xml File and binding interfaces must be in a package with the same name-->
        <mapper class="com.li.dao.UserMapper"/>
        <!--        Mode 3: package scan, Mapper.xml File and binding interfaces must be in a package with the same name-->
        <!--        <package name="com.li.dao"/>-->

    </mappers>

2. Life Cycle and Scope

Lifecycle and scope are important because errors can cause very serious concurrency problems

SqlSessionFactoryBuilder

  • It only needs to be created once to build the SqlSessionFactory,
  • Once the build succeeds, it is no longer needed
  • Optimal scope is local variable

SqlSessionFactory

  • Always exist once created
  • Database connection pool similar to JDBC
  • The best scope is global, such as using the singleton mode or static singleton mode

SqlSession

  • Request to connect to connection pool to execute SQL
  • Each thread has its own SqlSession, which is not thread safe
  • Use up needs to be closed to avoid waste of resources
  • The best scope is in the request or method scope

5. ResultMap Result Set Mapping

1. Inconsistent field names

When the field name of the database is inconsistent with the attribute name of the java entity class object, we need to use the return result set mapping in the mapper file.

Mode 1: Use result set mapping

<!--resultMap Equivalent to result set mapping when field and java When the attribute names of entity classes are inconsistent,
	Configuration mapping is required here, and consistent fields can be omitted-->
    <resultMap id="userMap" type="User">
        <!--id Labels correspond to those in the table id,Can be used directly result Label-->
        <!--In Label property Value Correspondence java Fields in entity classes, labels column Value corresponds to the corresponding field in the database, and if an alias is used, an alias is written-->
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="password" column="password"/>
    </resultMap>

    <!--  id Equivalent to method name, resultType Some fully qualified bits are required for the query result type(package path) parameterType Is Parameter Type-->
    <select id="getUserList" resultMap="userMap">
        select * from t_user
    </select>

Mode 2: Alias using SQL

For example, select id as t ID from t_ User

Alias inconsistent fields as consistent

Properties of Id and Result

attributedescribe
propertyField or property mapped to column results. If a JavaBean has a property with that name, it will be used first. Otherwise MyBatis will look for a field with a given name. In either case, you can navigate complex attributes using common point-separated forms. For example, you can map something simple like "username" or something complex like "address.street.number".
columnThe column name in the database, or the alias of the column. Typically, this is passed to the resultSet. The getString (columnName) method has the same parameters.
javaTypeThe fully qualified name of a Java class, or a type alias (refer to the table above for built-in type aliases). If you map to a JavaBean, MyBatis can usually infer types. However, if you are mapping to HashMap, you should explicitly specify a javaType to ensure that the behavior is what you expect.

2. Many-to-one problem

Entity Class

package com.li.pojo;

public class Teacher {
    private int id;
    private String name;
}
//Multiple students have a common student
public class Student {
    private int id;
    private String name;
    private Teacher teacher;
}

Interface of dao layer

package com.li.dao;

import com.li.pojo.Student;
import com.li.pojo.Teacher;

import java.util.List;

public interface StudentMapper {
    public List<Student> getStudentList();
    public List<Student> getStudentList2();
    public Teacher getTeacher(int id);
}

XML file

<mapper namespace="com.li.dao.StudentMapper">
    <!--Many-to-one approach One: Nesting by results Advantages Nesting results is easy to understand, but SQL Complex, that is, all required fields are found at once (recommended) -->
    <resultMap id="StudentMapper" type="student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
<!--        The third attribute of the student is Teacher Object Usage association Label mapping
            Use if it is a collection Collection Label mapping
-->
        <association property="teacher" javaType="teacher">
<!--            Attribute mapping for teachers-->
            <result property="id" column="tid"/>
            <result property="name" column="tname"/>
        </association>
    </resultMap>
<!--    Notice that all the attributes needed for an object are found-->
    <select id="getStudentList"  resultMap="StudentMapper">
        select s.id sid ,s.name sname ,t.name tname,t.id tid
        from t_student s join t_teacher t
        where s.tid = t.id;
    </select>

<!--    Mode 2: Advantages of using subtable query SQL Statement is simple, but mapping is complex -->
    <resultMap id="StudentMapper2" type="student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
<!--       This is done by first finding out the information in the students, then querying the teacher's table, and then matching the information,Low efficiency-->
<!--       
        <association property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
    </resultMap>
    <!-- Execute First-->
    <select id="getStudentList2" resultMap="StudentMapper2">
        select * from mytestdatabase.t_student
    </select>
        <!-- Post-Execution-->
   	<select id="getTeacher" resultType="teacher" parameterType="_int">
        select * from t_teacher where id = #{tid}
    </select>
    
    </mapper>

3. One-to-many problem

Entity class:

package com.li.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class Teacher2 {
    private int id;
    private String name;
    //There is a group of students in the teacher
    private List<Student2> student2s;
}
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Student2 {
    private int id ;
    private String name;
    //The student has a teacher's unique id
    private int tid;
}

dao interface:

package com.li.dao;

import com.li.pojo.Student2;
import com.li.pojo.Teacher2;
import org.apache.ibatis.annotations.Param;

public interface Teacher2Mapper {
    //The @Param annotation specifies the name of the interface's parameters when passed to the corresponding mapper file
    public Student2 getStudent2sByTid(@Param("tid")int id);
    public Teacher2 getTeacherByTid(@Param("tid") int id);
    public Teacher2 getTeacherByTid2(@Param("tid") int id);
}

mapper map:

<?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 Fill in the package path for the corresponding mapping interface-->
<mapper namespace="com.li.dao.Teacher2Mapper">

    <!--    One-to-many processing, mode one: result set nesting-->
    <resultMap id="Teacher2Mapper" type="Teacher2">
        <id property="id" column="tid"/>
        <result property="name" column="tname"/>
        <collection property="student2s" ofType="student2">
            <id property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>
    <select id="getTeacherByTid" parameterType="_int" resultMap="Teacher2Mapper">
        select s.id sid ,s.name sname,s.tid stid ,t.id tid,t.name tname
        from mytestdatabase.t_teacher t join mytestdatabase.t_student s on t.id = s.tid
        where t.id = #{tid}
    </select>
    
    
    <!--    One-to-many mode two:-->
    <resultMap id="Teacher2Mapper2" type="teacher2">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
<!--        And in that tag column Is Query sql Is the parameter element returned by the query java Collection type, ofType yes java Element types in a collection-->
        <collection property="student2s" javaType="ArrayList" ofType="student2" select="getStudent2sByTid" column="tid"/>
    </resultMap>
    
    <resultMap id="Student2Mapper2" type="student2">
        <id property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    </resultMap>
    //Execute First
        <select id="getTeacherByTid2" parameterType="_int" resultMap="Teacher2Mapper2">
            select t.id tid, t.name tname from mytestdatabase.t_teacher t where t.id = #{tid}
        </select>
    //Post-Execution
        <select id="getStudent2sByTid" resultMap = "Student2Mapper2">
            select s.name sname,s.id sid,s.tid tid from mytestdatabase.t_student s where tid = #{tid}
        </select>
</mapper>

4. Other questions:

1. Associated Nested Select Queries

attributedescribe
columnThe column name in the database, or the alias of the column. Typically, this is passed to the resultSet. The getString (columnName) method has the same parameters. Note: When using a composite primary key, you can use a syntax such as column="{prop1=col1,prop2=col2}" to specify multiple column names passed to a nested Select query statement. This causes PROP1 and prop2 to be the parameter objects and set as parameters for the corresponding nested Select statement.
selectThe ID of the mapping statement used to load complex type attributes, which retrieves data from the column specified by the column attribute and passes it as a parameter to the target select statement. See the example below for details. Note: When using a composite primary key, you can use a syntax such as column="{prop1=col1,prop2=col2}" to specify multiple column names passed to a nested Select query statement. This causes PROP1 and prop2 to be the parameter objects and set as parameters for the corresponding nested Select statement.
fetchTypeOptional. Valid values are lazy and eager. When a property is specified, the global configuration parameter lazyLoadingEnabled is ignored in the map and the value of the property is used.

VI. Logs

1. Log settings

Log usage needs to be explicitly opened in the mybatis configuration file and will be found automatically when not specified.

<settings>
    <!--Be careful not to have spaces-->
<setting name="logImpl" value="STDOUT_LOGGING"/>

2. Common logs are

  • 1.SLF4J
  • 2.LOG4J(deprecated since 3.5.9) [Master]
  • 3.LOG4J2
  • 4.JDK_LOGGING
  • 5.COMMONS_LOGGING
  • 6.STDOUT_LOGGING
  • 7.NO_LOGGING [Do not open log]

STDOUT_LOGGING Standard Log only needs to be explicitly opened, no need to import

3. LOG4J Log

1. What is LOG4J

  • Log4j is an open source project for Apache.

  • By using Log4j, we can control log information delivery to consoles, files, GUI components, even set interface servers, NT event loggers, UNIX Syslog [daemons, and so on;

  • We can also control the output format of each log.

  • By defining the level of each log information, we can control the generation of the log in more detail.

  • These can be configured flexibly through a configuration file without modifying the applied code.

2. Use of LOG4J

1. First import the corresponding jar package

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>

2. Configure log4j configuration file

#Export log information at the DEBUG level to two destinations console and file, defined in the following code
log4j.rootLogger=DEBUG,console,file

#Settings for 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

#Settings for file output
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/li.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. Declare in the mybatis configuration file

<settings>
    <!--Be careful not to have spaces-->
<setting name="logImpl" value="LOG4J"/>

After configuring the above, mybatis can be used automatically

Of course, log4j does more than that, its custom use

package com.li.dao;

import com.li.pojo.Teacher2;
import com.li.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Test;

public class Teacher2Test {
    
    //1. Define a global static variable
    //Be careful not to reverse error pack org.apache.log4j.Logger;
    static Logger logger = Logger.getLogger(Teacher2Test.class);
    @Test
    public void selectTest(){
        //2. Use
        //Output the information you want
        logger.info("[info]Enter selectTest()Method");
        logger.debug("[debug]Enter selectTest()Method");
        logger.error("[error]Enter selectTest()Method");
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        Teacher2Mapper teacher2Mapper = sqlSession.getMapper(Teacher2Mapper.class);
        Teacher2 teacher2 = teacher2Mapper.getTeacherByTid(2);
        System.out.println(teacher2);
        sqlSession.close();
    }
}

7. Paging Problem

1. SQL Paging

SQL syntax:

select * from t_user limit startIndex,pageSize;
seletc * from t_user limit pageSize;

Queries start with startIndex, showing pageSize per page. If startIndex is omitted, queries start from 0 by default

Query page n data:

select * from t_user limit (n-1)*pageSize,pageSize;

2. RowBounds Paging

dao interface method

public List<User> getUserByRowBounds();

mapper

    <select id="getUserByRowBounds" resultMap="UserMap">
        select * from t_user;
    </select>

java code

    public void rowBoundsTest(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        //Paging at the Java code level
        //Construction method passes start page and size per page
        RowBounds rowBounds = new RowBounds(1,2);
        //Note that the third parameter of the selectList() method passes a RowBounds object, and the second parameter is not used to be empty
        List<User> lists = sqlSession.selectList("com.li.dao.UserMapper.getUserByRowBounds",null,rowBounds);
        for (int i = 0; i < lists.size(); i++) {
            System.out.println(lists.get(i));
        }
        sqlSession.close();
    }

8. mybatis Annotation Development

1. Benefits of Interface-oriented programming

  • Decoupling, expandable, multiplexed
  • In hierarchical development, the upper level does not care about the specific implementation
  • Compliance with common standards makes development easier and more normative

Three different facets:

  • Object-oriented means that when we consider a problem, we consider its properties and methods in terms of objects.
  • Process-oriented means that when we consider a problem, we consider its implementation in terms of a specific process (transaction process).
  • Interface design and non-interface design are for reuse technology. They are not a problem with object-oriented (process), but more reflect the overall system architecture.

2. Develop using annotations

Use annotations in dao layer interfaces, for example:

	@Select("select * from t_user where name like '%${name}%'")
    public List<User> selectUserByLike(String name);
	
    public int addUser(User user);
    public int updateUser(User user);
    //If you use the @Param() annotation, the naming in the annotation takes precedence in sql, but it is not appropriate for complex types
    // If a parameter has only one basic type, it can be omitted, and if there are multiple parameters, the comment is required before each parameter
  	@Insert("insert into t_user(id,password,name) value (#{id},#{password},#{name})")
    public int addUser(User user);
    @Update("update t_user set name = #{name} ,password = #{password} where id = #{id}")
    public int updateUser(User user);
    //If the @Param() comment is used, the naming in the comment takes precedence in sql, and if the parameter has only one basic type, it can be omitted
    // If there are multiple parameters, the comment is required before each parameter
    @Delete("delete from t_user where id = #{id}")
    public int deleteUser(@Param("id") int id);
    @Delete("delete from t_user where id = #{id}")
    public int deleteUser(@Param("id") int id);

Matters needing attention:

  • The annotated method can no longer be used in the corresponding Mapper. Configure SQL statements in xml, otherwise errors will occur, you can no longer configure mapper files using annotations
  • Developing with annotations still requires registering the corresponding interface in the mybatis configuration file
  • Comments are not appropriate for complex sql statements

Register dao interface in mybatis configuration file

<mappers>
    <mapper class="xiaoqi.dao.UserMapper"></mapper>
</mappers>

mybatis Notes Development Principles:

  • Bottom implementation mechanism: reflection

  • Bottom level: dynamic proxy

9. mybatis execution process

1. What is SqlSession

  • SqlSession is a key object of MyBatis.

  • Is exclusive to performing persistence operations, similar to Connection in JDBC.

  • It is a ** single-threaded object that interacts between applications and the persistence layer, and ** is a key object for MyBatis to perform persistence operations.

  • The SqlSession object completely contains all the methods of executing SQL operations against the background of the database, and its underlying layer encapsulates JDBC connections [Key]

  • A mapped SQL statement can be executed directly with a SqlSession instance

  • Each thread should have its own SqlSession instance. **

  • Instances of SqlSession cannot be shared and SqlSession is thread insecure

  • It is absolutely impossible to say that a reference to an SqlSeesion instance is placed in a static field of a class or even an instance field. Also, you must never place references to SqlSession instances in any type of administrative scope, such as the HttpSession object in a Servlet. Closing Session after using SqlSeesion is important and you should make sure that you use the finally block to close it.

2. Creation process of SqlSession

  • 1.SqlSessionFactoryBuilder—>SqlSessionFactory—>SqlSession

  • 2.SqlSessionFactoryBuilder only needs to be created once and is recommended to be created using local objects

  • 3.SqlSessionFactoryBuilder can build a SqlSessionFactory instance from an XML Configuration file [mybatis core Configuration file] or a **preconfiguration instance ****.

  • 4. Now that we have the SqlSessionFactory, we can get an instance of SqlSession from it.

mybatis executes the process,

10. Dynamic SQL

1,, when and if tags

<!--    where Labels only return anything in child elements (they may not if But if there is content), insert " WHERE" Clause.
		Moreover, if the beginning of a clause is " AND" Or " OR",where Labels also remove them-->

<!-- if In Label test A value of is a conditional expression, and is added when the value is true if Content in Label
				For example:"title != null",Means to follow map Remove from collection key by title Of value,And make a judgment that the value is not empty
				-->

    <select id="selectBlogWhere" parameterType="map" resultType="blog">
        select * from mytestdatabase.t_blog
        <where>

            <if test="title != null">
                title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </where>
    </select>

2. choose Label

<!--   	Sometimes, we don't want to use all the conditions, we just want to choose one from many.
      	In response to this situation, MyBatis Provided choose Elements,
      	It's a little like Java In switch Sentence. Search in turn when in test The label whose property is true,
		If one when If the label is true, add the contents of the label, or add if none of them conforms otherwise Content in Label
		
-->
    <select id="selectBlogChoose" parameterType="map" resultType="blog">
        select * from mytestdatabase.t_blog
        <where>

            <choose>
                <when test="title != null">
                    title = #{title}
                </when>
                <when test="author != null">
                    and author = #{author}
                </when>
                <when test="views != null">
                    and views = #{views}
                </when>
                <otherwise>
                    and views >1000
                </otherwise>
            </choose>
        </where>

    </select>

3. set Label

	<!--    set Elements are dynamically inserted at the beginning of a line SET Keyword,
	Additional commas, introduced when assigning values to columns using conditional statements, are deleted.
	set In Label test True if Everything in the label will be added
	. -->
    <update id="updateBlog" parameterType="map">
        update t_blog
        <set>
            <if test="title != null">
                title = #{title},
            </if>
            <if test="author != null">
                author = #{author},
            </if>
            <if test="views != null">
                views = #{views}
            </if>
        </set>
        <where>
            id = #{id}
        </where>
    </update>

4. foreach tag

    
	<!--foreach and java Enhancements in for Similarly, from collection Property points to a collection, using item Value traversal to which property points
	If there are elements in the collection, the open Attribute points to a string as traversed'head',with separator The value that the property points to is a delimiter.
	with close Property points to the end of the string
	
	-->
<select id="selectForeach" parameterType="map" resultType="blog">
        select * from t_blog
        <where>
            <foreach collection="ids" item="id" open="and (" separator="or" close=")">
                id = #{id}
            </foreach>
        </where>
</select>

5. sql fragments

    <!--stay mapper Files can be used SQL Tag to define a SQL Fragment,
	And can be used elsewhere in the file include A note refers to the passage,
	To improve code utilization
	-->
<sql id="title-author-views-if">
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
        <if test="views != null">
            and author = #{views}
        </if>
</sql>
<select id="selectBlogIf" parameterType="map" resultType="blog">
        select * from mytestdatabase.t_blog 
        <where>
            <include refid="title-author-views-if"></include>
        </where>

</select>

11. Caching issues

1. Introduction to Caching

When you need to query the database frequently, you need to connect data frequently, which is very resource-intensive!

If we give him the result of a query, give him a temporary place to get it! For example, in memory, we can cache it, and when we query the same data again, we go directly to the cache instead of the database.

1. What is Cache?

Temporary data in existence
By putting the data that users often query in the cache (memory), users can query data from the cache without querying from disk (relational database data files), which improves query efficiency and solves the performance problem of high concurrent systems.
2. Why use caching?

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 queried frequently and changes infrequently [Cache can be used]
Cache in Mybatis:
Mybatis includes a very powerful query cache feature that makes it very easy to customize and configure the cache. Caching can greatly improve query efficiency.

By default, the Mybatis system defines two levels of caching: first-level caching and second-level caching.

By default, only one level of cache is turned on. (SqlSession level cache, also known as undergraduate cache)
The secondary cache, which is namespace-based, requires manual opening and configuration
To improve scalability, Mybatis defines the cache interface Cache. We can customize the secondary cache by implementing the Cache interface

2. Level 1 Cache

Level 1 cache is also called local cache: SqlSession

  • Data queried during the same session as the database is placed in the local cache
  • If you need to get the same data later, take it directly from the cache, there is no need to query the database

Cache test (log needs to be turned on first):

Query statement:

    @Test
    public void selectTest2(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.selectUserById(1);
        System.out.println(user);
        sqlSession.close();
    }

Result:

If we query the same result multiple times in a row

    @Test
    public void selectTest2(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.selectUserById(1);
        User user1 = userMapper.selectUserById(1);
        User user2 = userMapper.selectUserById(1);
        System.out.println(user);
        System.out.println(user1);
        System.out.println(user2);
        sqlSession.close();
    }

Result: Queried only once, obviously the second and third time the cache was queried

This is a SqlSession cache: Level 1 cache

When the first level cache also fails, for example:

1. Query different things

    @Test
    public void selectTest2(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.selectUserById(1);
        User user1 = userMapper.selectUserById(2);

        System.out.println(user);
        System.out.println(user1);

        sqlSession.close();
    }

Result: Queried twice

2. Additions and deletions occur during the query, which necessarily updates the cache

    @Test
    public void selectTest2(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.selectUserById(1);
        userMapper.deleteUser(4);
        User user1 = userMapper.selectUserById(1);
        System.out.println(user);
        System.out.println(user1);


        sqlSession.close();
    }

Result: It is obvious that after the deletion operation, the same content was queried twice

3. Query different Mapper

Different mapper content is significantly different

4. Clean up the cache manually

    @Test
    public void selectTest2(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.selectUserById(1);
        //Refresh cache manually
        sqlSession.clearCache();
        
        User user1 = userMapper.selectUserById(1);
        System.out.println(user);
        System.out.println(user1);


        sqlSession.close();
    }

Result: Query twice

Summary: Level 1 caching is on by default and only works once in SqlSession, that is, when a connection is connected and closed

One level cache is a map

3. Secondary Cache

  • Second-level cache is also called global cache. First-level cache has too low effect, so second-level cache is born.
  • A namespace-level cache, a namespace, corresponding to a secondary cache;
    Working mechanism;
  • When a session queries a piece of data, it is placed in the first level cache of the current session.
    If the current session is closed, the corresponding first-level cache for that session will be gone. But what we want is that the session is closed and the data in the first level cache is saved in the second level cache. New session queries for information to get content from the secondary cache
  • Data found by different mapper s is placed in their own cache (map)

Steps to use the secondary cache

1. The open cache shown in the settings tag in the mybatis configuration file (actually, by default, the open cache only needs to be configured in the mapper file)

<setting name="cacheEnabled" value="true"/>
cacheEnabledTurn on or off any caches configured in all mapper profiles globally.true | falsetrue

2. Turn on the cache in the mapper file

The easiest way to open

<cache/>

Configure Cache

    <cache
            eviction="FIFO"
            flushInterval="60000"
            size="512"
            readOnly="true"/>
<!--    
	This more advanced configuration creates a FIFO[FIFO) Caching,
	Refresh every 60 seconds,
    A maximum of 512 references can store result objects or lists.
	
    And the returned object is considered read-only,
    Therefore, modifying them may conflict with callers in different threads.
	eviction Cleanup strategies are: LRU[default][Clean up the least used) FIFO[FIFO, SOFT[Soft Reference) WEAK[Weak References)
-->

Test:

    @Test
    public void selectTest2(){
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        SqlSession sqlSession1 = MybatisUtil.getSqlSession();

        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.selectUserById(1);

        System.out.println(user);
        sqlSession.close();

        //Turn off the first sqlSession to save data from the first level cache to the second level cache

        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
        User user1 = userMapper1.selectUserById(1);
        System.out.println(user);
        System.out.println(user1==user);

        sqlSession1.close();
    }

Result: Query the database only once, and the closed connection is returned again

Summary:

  • Only valid under the same Mapper as long as the secondary cache is turned on

  • All data is first placed in the first level cache; Only when a session is committed or closed will it be committed to the secondary cache

Caching principles

4. Custom Cache - ehcache

Ehcache is a widely used open source Java distributed cache, mainly for general purpose caching

To use ehcache in your program:

1. First import the ehcache package, note that mybatis-ehcache

    <!-- 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. Write ehcache profile

<?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: For the cache path, ehcache This property 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 caching policy is used when a 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 set, timeout Will not work.
      overflowToDisk:Whether to save to disk when the system crashes
      timeToIdleSeconds:Sets the allowable idle time (in seconds) for the object before it expires. Only if eternal=false Object is not permanently valid, optional property, default value is 0, that is, infinite idle time.
      timeToLiveSeconds:Sets the allowable lifetime (in seconds) for an object before it fails. The maximum time is between creation time and expiration time. Only if eternal=false Used when the object is not permanently valid, defaulting to 0.,That is, the object has an infinite lifetime.
      diskPersistent: Whether to cache virtual machine restart period 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). Default is 30 MB. each Cache They should all have their own buffer.
      diskExpiryThreadIntervalSeconds: Disk failure threads run at intervals of 120 seconds by default.
      memoryStoreEvictionPolicy: When reached maxElementsInMemory When restricted, Ehcache Memory will be cleaned up according to the specified policy. The default policy is LRU(Least recently used). You can set it to FIFO(FIFO) or LFU(Less used).
      clearOnFlush: Whether to clear when the maximum amount of memory is available.
      memoryStoreEvictionPolicy:Optional strategies are: LRU(Least recently used, default policy), FIFO(FIFO), LFU(Minimum visits).
      FIFO,first in first out,This is the most familiar, FIFO.
      LFU, Less Frequently Used,That's the strategy used in the example above. To be frank, it's the least used strategy ever. As mentioned above, a cached element has one hit Properties, hit The minimum value will be flushed out of the cache.
      LRU,Least Recently Used,The least recently used cached element has a timestamp, and when the cache is full and you need to make room to cache new elements, the element with the farthest timestamp from the current time in the existing cached element will be flushed out of the cache.
   -->
</ehcache>

3. Configure in mapper file

    <cache type = "org.mybatis.caches.ehcache.EhcacheCache" />

4. Use only

Creation is not easy, thank you for your support

Keywords: Java Maven Mybatis SSM

Added by Chrisww on Wed, 23 Feb 2022 19:19:45 +0200