[Mybatis tutorial] Persistence layer framework, the most complete Mybatis tutorial in history, one article that teaches you to use Mybatis for database operations in project development

Introduction to Mybatis

MyBatis History

  • MyBatis was originally iBatis, an open source project of Apache. In June 2010, this project was migrated to Google Code by the Apache Software Foundation. As the development team transferred to Google Code, iBatis3.x was officially renamed MyBatis. Code migrated to Github in November 2013
  • The word iBatis comes from the combination of "internet" and "abatis" and is a persistence layer framework based on Java. The persistence layer framework provided by iBatis includes SQL Maps and Data Access Objects (DAO)

MyBatis features

  1. MyBatis is an excellent persistence layer framework that supports customized SQL, stored procedures and advanced mapping.
  2. MyBatis avoids almost all JDBC code and manual setting of parameters and obtaining result sets
  3. MyBatis can use simple XML or annotations for configuration and original mapping, mapping interfaces and Java POJOs (Plain Old Java Objects, ordinary Java objects) into records in the database
  4. MyBatis is a semi-automatic ORM (Object Relation Mapping) framework

MyBatis download

Comparison with other persistence layer technologies

  • JDBC
    • SQL is mixed in Java code with a high degree of coupling, causing internal damage to hard coding.
    • Maintenance is difficult and SQL changes in actual development requirements, and frequent modifications are common.
    • Long code and low development efficiency
  • Hibernate and JPA
    • Easy to operate and high development efficiency
    • Long and complex SQL in the program needs to bypass the framework
    • SQL automatically generated internally is not easy to perform special optimization.
    • Based on a fully automatic framework for full mapping, it is difficult to partially map POJOs with a large number of fields.
    • Too many reflection operations cause database performance to degrade
  • MyBatis
    • Lightweight, great performance
    • SQL and Java coding are separated and functional boundaries are clear. Java code focuses on business, SQL statements focus on data
    • Development efficiency is slightly lower than HIbernate, but completely acceptable

Build MyBatis

development environment

  • IDE: idea 2023.2
  • Build tool: maven 3.5.4
  • MySQL version: MySQL 5.7
  • MyBatis version: MyBatis 3.5.7

Create maven project

  • Packaging method: jar

  • Introduce dependencies

    <dependencies>
    	<!-- Mybatis核心 -->
    	<dependency>
    		<groupId>org.mybatis</groupId>
    		<artifactId>mybatis</artifactId>
    		<version>3.5.7</version>
    	</dependency>
    	<!-- junit测试 -->
    	<dependency>
    		<groupId>junit</groupId>
    		<artifactId>junit</artifactId>
    		<version>4.12</version>
    		<scope>test</scope>
    	</dependency>
    	<!-- MySQL驱动 -->
    	<dependency>
    		<groupId>mysql</groupId>
    		<artifactId>mysql-connector-java</artifactId>
    		<version>5.1.3</version>
    		</dependency>
    </dependencies>
    

Create the core configuration file of MyBatis

It is customary to name itmybatis-config.xml. This file name is only a suggestion, not a requirement. After Spring is integrated in the future, this configuration file can be omitted, so you can copy and paste it directly during operation.
The core configuration file is mainly used to configure the environment for connecting to the database and the global configuration information of MyBatis.
The core configuration file is stored in the src/main/resources directory< /span>

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE configuration  
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
"http://mybatis.org/dtd/mybatis-3-config.dtd">  
<configuration>  
	<!--设置连接数据库的环境-->  
	<environments default="development">  
		<environment id="development">  
			<transactionManager type="JDBC"/>  
			<dataSource type="POOLED">  
				<property name="driver" value="com.mysql.cj.jdbc.Driver"/>  
				<!--数据库ip地址(默认为本机localhost)以及端口号(默认端口号3306)以及数据库名称(我的是Mybatis)-->  
				<property name="url" value="jdbc:mysql://localhost:3306/MyBatis"/>  
				<!--数据库用户名-->
				<property name="username" value="root"/>   
				<!-- 数据库密码-->
				<property name="password" value="1234"/>  
			</dataSource>  
		</environment>  
	</environments>  
	<!--引入映射文件-->  
	<mappers>  
		<mapper resource="mappers/UserMapper.xml"/>  
	</mappers>  
</configuration>

Create mapper interface

The mapper interface in MyBatis is equivalent to the previous dao. But the difference is that mapper is just an interface, we don't need to provide an implementation class

package com.atguigu.mybatis.mapper;  
  
public interface UserMapper {
    
      
	/**  
	* 添加用户信息  
	*/  
	int insertUser();  
}

Create MyBatis mapping file

  • Related concepts: ORM (Object Relationship Mapping) object relationship mapping.
    • Object: Java entity class object
    • Relational: relational database
    • Mapping: the correspondence between the two
Java concepts Database concepts
kind surface
Attributes Field/Column
object record/row
  • Naming rules for mapping files
    • The class name of the entity class corresponding to the table + Mapper.xml
    • For example: table t_user, the mapped entity class is User, and the corresponding mapping file is UserMapper.xml
    • Therefore, a mapping file corresponds to an entity class and corresponds to the operation of a table.
    • MyBatis mapping files are used to write SQL, access and operate data in the table
    • The location where MyBatis mapping files are stored is in the src/main/resources/mappers directory.
  • In MyBatis, data can be manipulated interface-oriented, and the two must be consistent.
    • The full class name of the mapper interface is consistent with the namespace of the mapping file.
    • The method name of the method in the mapper interface is consistent with the id attribute of the label writing SQL in the mapping file.
<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE mapper  
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">  
<mapper namespace="com.atguigu.mybatis.mapper.UserMapper">  
	<!--int insertUser();-->  
	<insert id="insertUser">  
		insert into t_user values(null,'张三','123',23,'女')  
	</insert>  
</mapper>

Test functionality via junit

  • SqlSession: Represents the session between the Java program and the database. (HttpSession is the session between the Java program and the browser)
  • SqlSessionFactory: is the "factory" that "produces" SqlSession
  • Factory pattern: If the process used to create an object is basically fixed, then we can encapsulate the relevant code for creating this object into a "factory class", and use this factory class to "produce" the objects we need in the future.
public class UserMapperTest {
    
    
    @Test
    public void testInsertUser() throws IOException {
    
    
        //读取MyBatis的核心配置文件
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        //获取SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //通过核心配置文件所对应的字节输入流创建工厂类SqlSessionFactory,生产SqlSession对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
        //获取sqlSession,此时通过SqlSession对象所操作的sql都必须手动提交或回滚事务
        //SqlSession sqlSession = sqlSessionFactory.openSession();
	    //创建SqlSession对象,此时通过SqlSession对象所操作的sql都会自动提交  
		SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //通过代理模式创建UserMapper接口的代理实现类对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        //调用UserMapper接口中的方法,就可以根据UserMapper的全类名匹配元素文件,通过调用的方法名匹配映射文件中的SQL标签,并执行标签中的SQL语句
        int result = userMapper.insertUser();
        //提交事务
        //sqlSession.commit();
        System.out.println("result:" + result);
    }
}
  • At this time, the transaction needs to be submitted manually. If you want to automatically submit the transaction, use SqlSession sqlSession = sqlSessionFactory.openSession(true); when obtaining the sqlSession object, and pass in a Boolean type parameter with a value of true, so that Can be submitted automatically

Add log4j logging function

  1. Add dependencies
    <!-- log4j日志 -->
    <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
    </dependency>
    
  2. Add log4j configuration file
    • The log4j configuration file is named log4j.xml and is stored in the src/main/resources directory.
    • Log level: FATAL(fatal)>ERROR(error)>WARN(warning)>INFO(information)>DEBUG(debug) The content printed from left to right becomes more and more detailed.
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
        <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
            <param name="Encoding" value="UTF-8" />
            <layout class="org.apache.log4j.PatternLayout">
    			<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
            </layout>
        </appender>
        <logger name="java.sql">
            <level value="debug" />
        </logger>
        <logger name="org.apache.ibatis">
            <level value="info" />
        </logger>
        <root>
            <level value="debug" />
            <appender-ref ref="STDOUT" />
        </root>
    </log4j:configuration>
    

Detailed explanation of core configuration files

The tags in the core configuration file must be in a fixed order (some tags can be omitted, but the order must not be messed up):
properties, settings, typeAliases, typeHandlers, objectFactory, objectWrapperFactory, reflectorFactory, plugins, environments, databaseIdProvider, mappers

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//MyBatis.org//DTD Config 3.0//EN"
        "http://MyBatis.org/dtd/MyBatis-3-config.dtd">
<configuration>
    <!--引入properties文件,此时就可以${属性名}的方式访问属性值-->
    <properties resource="jdbc.properties"></properties>
    <settings>
        <!--将表中字段的下划线自动转换为驼峰-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!--开启延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>
    <typeAliases>
        <!--
        typeAlias:设置某个具体的类型的别名
        属性:
        type:需要设置别名的类型的全类名
        alias:设置此类型的别名,且别名不区分大小写。若不设置此属性,该类型拥有默认的别名,即类名
        -->
        <!--<typeAlias type="com.atguigu.mybatis.bean.User"></typeAlias>-->
        <!--<typeAlias type="com.atguigu.mybatis.bean.User" alias="user">
        </typeAlias>-->
        <!--以包为单位,设置改包下所有的类型都拥有默认的别名,即类名且不区分大小写-->
        <package name="com.atguigu.mybatis.bean"/>
    </typeAliases>
    <!--
    environments:设置多个连接数据库的环境
    属性:
	    default:设置默认使用的环境的id
    -->
    <environments default="mysql_test">
        <!--
        environment:设置具体的连接数据库的环境信息
        属性:
	        id:设置环境的唯一标识,可通过environments标签中的default设置某一个环境的id,表示默认使用的环境
        -->
        <environment id="mysql_test">
            <!--
            transactionManager:设置事务管理方式
            属性:
	            type:设置事务管理方式,type="JDBC|MANAGED"
	            type="JDBC":设置当前环境的事务管理都必须手动处理
	            type="MANAGED":设置事务被管理,例如spring中的AOP
            -->
            <transactionManager type="JDBC"/>
            <!--
            dataSource:设置数据源
            属性:
	            type:设置数据源的类型,type="POOLED|UNPOOLED|JNDI"
	            type="POOLED":使用数据库连接池,即会将创建的连接进行缓存,下次使用可以从缓存中直接获取,不需要重新创建
	            type="UNPOOLED":不使用数据库连接池,即每次使用连接都需要重新创建
	            type="JNDI":调用上下文中的数据源
            -->
            <dataSource type="POOLED">
                <!--设置驱动类的全类名-->
                <property name="driver" value="${jdbc.driver}"/>
                <!--设置连接数据库的连接地址-->
                <property name="url" value="${jdbc.url}"/>
                <!--设置连接数据库的用户名-->
                <property name="username" value="${jdbc.username}"/>
                <!--设置连接数据库的密码-->
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--引入映射文件-->
    <mappers>
        <!-- <mapper resource="UserMapper.xml"/> -->
        <!--
        以包为单位,将包下所有的映射文件引入核心配置文件
        注意:
			1. 此方式必须保证mapper接口和mapper映射文件必须在相同的包下
			2. mapper接口要和mapper映射文件的名字一致
        -->
        <package name="com.atguigu.mybatis.mapper"/>
    </mappers>
</configuration>
  • Insert image description here

Default type alias

Insert image description here

Insert image description here

Add, delete, modify and query MyBatis

  1. Add to
    <!--int insertUser();-->
    <insert id="insertUser">
    	insert into t_user values(null,'admin','123456',23,'男','[email protected]')
    </insert>
    
  2. delete
    <!--int deleteUser();-->
    <delete id="deleteUser">
        delete from t_user where id = 6
    </delete>
    
  3. Revise
    <!--int updateUser();-->
    <update id="updateUser">
        update t_user set username = '张三' where id = 5
    </update>
    
  4. Query an entity class object
    <!--User getUserById();-->  
    <select id="getUserById" resultType="com.atguigu.mybatis.bean.User">  
    	select * from t_user where id = 2  
    </select>
    
  5. Query collection
    <!--List<User> getUserList();-->
    <select id="getUserList" resultType="com.atguigu.mybatis.bean.User">
    	select * from t_user
    </select>
    
  • Notice:

    1. The label select of the query must set the attribute resultType or resultMap, which is used to set the mapping relationship between the entity class and the database table.
      • resultType: automatic mapping, used when the attribute name is consistent with the field name in the table
      • resultMap: Custom mapping, used for one-to-many or many-to-one situations or when field names and attribute names are inconsistent
    2. When there are multiple pieces of data queried, entity classes cannot be used as the return value, only collections can be used, otherwise TooManyResultsException will be thrown; but if there is only one piece of data queried, entity classes or collections can be used as the return value.

Two ways for MyBatis to obtain parameter values ​​(key points)

  • MyBatis has two ways to obtain parameter values: ${} and #{}. It is recommended to use #{} to prevent the risk of SQL injection.
  • The essence of ${} is string concatenation, and the essence of #{} is placeholder assignment.
  • ${} uses string splicing to splice sql. If you assign a value to a string type or date type field, you need to manually add single quotes; but #{} uses placeholder assignment to splice sql. In this case, it is a character When assigning values ​​to fields of string type or date type, single quotes can be added automatically.

A parameter of a single literal type

  • If the method parameter in the mapper interface is a single literal type, you can use ${} and #{} to obtain the value of the parameter with any name (it is best to recognize the name). Note that ${} needs to be added manually. quotation marks
<!--User getUserByUsername(String username);-->
<select id="getUserByUsername" resultType="User">
	select * from t_user where username = #{username}
</select>
<!--User getUserByUsername(String username);-->
<select id="getUserByUsername" resultType="User">  
	select * from t_user where username = '${username}'  
</select>

Parameters of multiple literal types

  • If there are multiple method parameters in the mapper interface, MyBatis will automatically put these parameters in a map collection.

    1. Use arg0, arg1... as keys and parameters as values;
    2. Use param1, param2... as keys and parameters as values;
  • Therefore, you only need to access the key of the map collection through ${} and #{} to obtain the corresponding value. Note that ${} needs to be manually added in single quotes.

  • You can use arg or param. It should be noted that arg starts from arg0 and param starts from param1.

<!--User checkLogin(String username,String password);-->
<select id="checkLogin" resultType="User">  
	select * from t_user where username = #{arg0} and password = #{arg1}  
</select>
<!--User checkLogin(String username,String password);-->
<select id="checkLogin" resultType="User">
	select * from t_user where username = '${param1}' and password = '${param2}'
</select>

map collection type parameters

  • If the method in the mapper interface requires multiple parameters, you can manually create a map collection. To put these data in the map, you only need to access the keys of the map collection through ${} and #{} to obtain the corresponding data. Value, note that ${} needs to be manually added in single quotes
<!--User checkLoginByMap(Map<String,Object> map);-->
<select id="checkLoginByMap" resultType="User">
	select * from t_user where username = #{username} and password = #{password}
</select>
@Test
public void checkLoginByMap() {
    
    
	SqlSession sqlSession = SqlSessionUtils.getSqlSession();
	ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
	Map<String,Object> map = new HashMap<>();
	map.put("usermane","admin");
	map.put("password","123456");
	User user = mapper.checkLoginByMap(map);
	System.out.println(user);
}

Entity class type parameters

  • If the method parameter in the mapper interface is an entity class object, you can use ${} and #{} to obtain the attribute value by accessing the attribute name in the entity class object. Note that ${} needs to be manually added in single quotes.
<!--int insertUser(User user);-->
<insert id="insertUser">
	insert into t_user values(null,#{username},#{password},#{age},#{sex},#{email})
</insert>
@Test
public void insertUser() {
    
    
	SqlSession sqlSession = SqlSessionUtils.getSqlSession();
	ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
	User user = new User(null,"Tom","123456",12,"男","[email protected]");
	mapper.insertUser(user);
}

Use @Param to identify parameters

  • The method parameters in the mapper interface can be identified through the @Param annotation. At this time, these parameters will be placed in the map collection.

    1. Use the value attribute value of the @Param annotation as the key and the parameter as the value;
    2. Use param1, param2... as keys and parameters as values;
  • You only need to access the key of the map collection through ${} and #{} to get the corresponding value. Note that ${} needs to be manually added with single quotes.

<!--User CheckLoginByParam(@Param("username") String username, @Param("password") String password);-->
    <select id="CheckLoginByParam" resultType="User">
        select * from t_user where username = #{username} and password = #{password}
    </select>
@Test
public void checkLoginByParam() {
    
    
	SqlSession sqlSession = SqlSessionUtils.getSqlSession();
	ParameterMapper mapper = sqlSession.getMapper(ParameterMapper.class);
	mapper.CheckLoginByParam("admin","123456");
}

Summarize

  • It is recommended to handle it in two situations

    1. Entity class type parameters
    2. Use @Param to identify parameters

Various query functions of MyBatis

  1. If there is only one piece of data queried, you can use
    1. Entity class object receives
    2. List collection receives
    3. Map collection receives, the result{password=123456, sex=男, id=1, age=23, username=admin}
  2. If there are multiple pieces of queried data, it must not be received using entity class objects, and TooManyResultsException will be thrown. You can pass
    1. LSt collection of entity class type is received
    2. List collection of Map type receives
    3. Add the @MapKey annotation to the method of the mapper interface

Query an entity class object

/**
 * 根据用户id查询用户信息
 * @param id
 * @return
 */
User getUserById(@Param("id") int id);
<!--User getUserById(@Param("id") int id);-->
<select id="getUserById" resultType="User">
	select * from t_user where id = #{id}
</select>

Query a List collection

/**
 * 查询所有用户信息
 * @return
 */
List<User> getUserList();
<!--List<User> getUserList();-->
<select id="getUserList" resultType="User">
	select * from t_user
</select>

Query single data

/**  
 * 查询用户的总记录数  
 * @return  
 * 在MyBatis中,对于Java中常用的类型都设置了类型别名  
 * 例如:java.lang.Integer-->int|integer  
 * 例如:int-->_int|_integer  
 * 例如:Map-->map,List-->list  
 */  
int getCount();
<!--int getCount();-->
<select id="getCount" resultType="_integer">
	select count(id) from t_user
</select>

Query a piece of data as a map collection

/**  
 * 根据用户id查询用户信息为map集合  
 * @param id  
 * @return  
 */  
Map<String, Object> getUserToMap(@Param("id") int id);
<!--Map<String, Object> getUserToMap(@Param("id") int id);-->
<select id="getUserToMap" resultType="map">
	select * from t_user where id = #{id}
</select>
<!--结果:{password=123456, sex=男, id=1, age=23, username=admin}-->

Query multiple pieces of data as a map collection

method one

/**  
 * 查询所有用户信息为map集合  
 * @return  
 * 将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,此时可以将这些map放在一个list集合中获取  
 */  
List<Map<String, Object>> getAllUserToMap();
<!--Map<String, Object> getAllUserToMap();-->  
<select id="getAllUserToMap" resultType="map">  
	select * from t_user  
</select>
<!--
	结果:
	[{password=123456, sex=男, id=1, age=23, username=admin},
	{password=123456, sex=男, id=2, age=23, username=张三},
	{password=123456, sex=男, id=3, age=23, username=张三}]
-->

Method Two

/**
 * 查询所有用户信息为map集合
 * @return
 * 将表中的数据以map集合的方式查询,一条数据对应一个map;若有多条数据,就会产生多个map集合,并且最终要以一个map的方式返回数据,此时需要通过@MapKey注解设置map集合的键,值是每条数据所对应的map集合
 */
@MapKey("id")
Map<String, Object> getAllUserToMap();
<!--Map<String, Object> getAllUserToMap();-->
<select id="getAllUserToMap" resultType="map">
	select * from t_user
</select>
<!--
	结果:
	{
	1={password=123456, sex=男, id=1, age=23, username=admin},
	2={password=123456, sex=男, id=2, age=23, username=张三},
	3={password=123456, sex=男, id=3, age=23, username=张三}
	}
-->

Execution of special SQL

fuzzy query

/**
 * 根据用户名进行模糊查询
 * @param username 
 * @return java.util.List<com.atguigu.mybatis.pojo.User>
 * @date 2022/2/26 21:56
 */
List<User> getUserByLike(@Param("username") String username);
<!--List<User> getUserByLike(@Param("username") String username);-->
<select id="getUserByLike" resultType="User">
	<!--select * from t_user where username like '%${mohu}%'-->  
	<!--select * from t_user where username like concat('%',#{mohu},'%')-->  
	select * from t_user where username like "%"#{mohu}"%"
</select>
  • Among themselect * from t_user where username like "%"#{mohu}"%" is the most commonly used

batch deletion

  • can only use ${}. If #{} is used, the parsed sql statement is delete from t_user where id in ('1,2,3'), so 1,2,3 is regarded as As a whole, only the data with id 1,2,3 will be deleted. The correct statement should be delete from t_user where id in (1,2,3), or delete from t_user where id in ('1','2','3')
/**
 * 根据id批量删除
 * @param ids 
 * @return int
 * @date 2022/2/26 22:06
 */
int deleteMore(@Param("ids") String ids);
<delete id="deleteMore">
	delete from t_user where id in (${ids})
</delete>
//测试类
@Test
public void deleteMore() {
    
    
	SqlSession sqlSession = SqlSessionUtils.getSqlSession();
	SQLMapper mapper = sqlSession.getMapper(SQLMapper.class);
	int result = mapper.deleteMore("1,2,3,8");
	System.out.println(result);
}

Dynamically set table name

  • You can only use ${} because the table name cannot be enclosed in single quotes.
/**
 * 查询指定表中的数据
 * @param tableName 
 * @return java.util.List<com.atguigu.mybatis.pojo.User>
 * @date 2022/2/27 14:41
 */
List<User> getUserByTable(@Param("tableName") String tableName);
<!--List<User> getUserByTable(@Param("tableName") String tableName);-->
<select id="getUserByTable" resultType="User">
	select * from ${tableName}
</select>

Add function to obtain auto-incremented primary key

  • scenes to be used
    • t_clazz(clazz_id,clazz_name)
    • t_student(student_id,student_name,clazz_id)
    1. Add class information
    2. Get the id of the newly added class
    3. Assign students to a class, that is, change the class ID of a certain school to the ID of a newly added class
  • Set two properties in mapper.xml
    • useGeneratedKeys: Set the primary key to use auto-increment
    • keyProperty: Because the unified return value for additions, deletions and modifications is the number of affected rows, the obtained auto-incremented primary key can only be placed in a certain attribute of the transmitted parameter user object.
/**
 * 添加用户信息
 * @param user 
 * @date 2022/2/27 15:04
 */
void insertUser(User user);
<!--void insertUser(User user);-->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
	insert into t_user values (null,#{username},#{password},#{age},#{sex},#{email})
</insert>
//测试类
@Test
public void insertUser() {
    
    
	SqlSession sqlSession = SqlSessionUtils.getSqlSession();
	SQLMapper mapper = sqlSession.getMapper(SQLMapper.class);
	User user = new User(null, "ton", "123", 23, "男", "[email protected]");
	mapper.insertUser(user);
	System.out.println(user);
	//输出:user{id=10, username='ton', password='123', age=23, sex='男', email='[email protected]'},自增主键存放到了user的id属性中
}

Custom mapping resultMap

resultMap handles the mapping relationship between fields and attributes

  • resultMap: Set custom mapping
    • Attributes:
      • id: represents the unique identifier of the custom mapping, which cannot be repeated.
      • type: The type of entity class to be mapped to the queried data
    • Sub tags:
      • id: Set the mapping relationship of the primary key
      • result: Set the mapping relationship of common fields
      • Subtag attributes:
        • property: Set the attribute name in the entity class in the mapping relationship
        • column: Set the field name in the table in the mapping relationship
  • If the field name is inconsistent with the attribute name in the entity class, you can set a custom mapping through resultMap. Even the attributes with the same field name and attribute name must be mapped, that is, all attributes must be listed.
<resultMap id="empResultMap" type="Emp">
	<id property="eid" column="eid"></id>
	<result property="empName" column="emp_name"></result>
	<result property="age" column="age"></result>
	<result property="sex" column="sex"></result>
	<result property="email" column="email"></result>
</resultMap>
<!--List<Emp> getAllEmp();-->
<select id="getAllEmp" resultMap="empResultMap">
	select * from t_emp
</select>
  • If the field name is inconsistent with the attribute name in the entity class, but the field name conforms to the rules of the database (use _), and the attribute name in the entity class conforms to the rules of Java (use camel case). At this time, the mapping relationship between field names and attributes in the entity class can also be handled in the following two ways:

    1. You can alias the fields to ensure they are consistent with the attribute names in the entity class.
      <!--List<Emp> getAllEmp();-->
      <select id="getAllEmp" resultType="Emp">
      	select eid,emp_name empName,age,sex,email from t_emp
      </select>
      
    2. You can set a global configuration information mapUnderscoreToCamelCase in the setting tag in the core configuration file of MyBatis, which can automatically convert the _ type field name to Camel case, for example: field name user_name, mapUnderscoreToCamelCase is set, then the field name will be converted to userName. Detailed explanation of core configuration files
    ```

Many-to-one mapping processing

Query employee information and department information corresponding to the employee

public class Emp {
    
      
	private Integer eid;  
	private String empName;  
	private Integer age;  
	private String sex;  
	private String email;  
	private Dept dept;
	//...构造器、get、set方法等
}

Processing mapping relationships in cascade mode

<resultMap id="empAndDeptResultMapOne" type="Emp">
	<id property="eid" column="eid"></id>
	<result property="empName" column="emp_name"></result>
	<result property="age" column="age"></result>
	<result property="sex" column="sex"></result>
	<result property="email" column="email"></result>
	<result property="dept.did" column="did"></result>
	<result property="dept.deptName" column="dept_name"></result>
</resultMap>
<!--Emp getEmpAndDept(@Param("eid")Integer eid);-->
<select id="getEmpAndDept" resultMap="empAndDeptResultMapOne">
	select * from t_emp left join t_dept on t_emp.eid = t_dept.did where t_emp.eid = #{eid}
</select>

Use association to handle mapping relationships

  • association: handles many-to-one mapping relationships
  • property: the property name that needs to handle multiple pairs of mapping relationships
  • javaType: the type of this attribute
<resultMap id="empAndDeptResultMapTwo" type="Emp">
	<id property="eid" column="eid"></id>
	<result property="empName" column="emp_name"></result>
	<result property="age" column="age"></result>
	<result property="sex" column="sex"></result>
	<result property="email" column="email"></result>
	<association property="dept" javaType="Dept">
		<id property="did" column="did"></id>
		<result property="deptName" column="dept_name"></result>
	</association>
</resultMap>
<!--Emp getEmpAndDept(@Param("eid")Integer eid);-->
<select id="getEmpAndDept" resultMap="empAndDeptResultMapTwo">
	select * from t_emp left join t_dept on t_emp.eid = t_dept.did where t_emp.eid = #{eid}
</select>

Step by step query

1. Query employee information
  • select: Set the unique identifier of SQL for distributed query (namespace.SQLId or the full class name of the mapper interface. Method name)
  • column: Set the conditions for step-by-step query
//EmpMapper里的方法
/**
 * 通过分步查询,员工及所对应的部门信息
 * 分步查询第一步:查询员工信息
 * @param  
 * @return com.atguigu.mybatis.pojo.Emp
 * @date 2022/2/27 20:17
 */
Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);
<resultMap id="empAndDeptByStepResultMap" type="Emp">
	<id property="eid" column="eid"></id>
	<result property="empName" column="emp_name"></result>
	<result property="age" column="age"></result>
	<result property="sex" column="sex"></result>
	<result property="email" column="email"></result>
	<association property="dept"
				 select="com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
				 column="did"></association>
</resultMap>
<!--Emp getEmpAndDeptByStepOne(@Param("eid") Integer eid);-->
<select id="getEmpAndDeptByStepOne" resultMap="empAndDeptByStepResultMap">
	select * from t_emp where eid = #{eid}
</select>
2. Query department information
//DeptMapper里的方法
/**
 * 通过分步查询,员工及所对应的部门信息
 * 分步查询第二步:通过did查询员工对应的部门信息
 * @param
 * @return com.atguigu.mybatis.pojo.Emp
 * @date 2022/2/27 20:23
 */
Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);
<!--此处的resultMap仅是处理字段和属性的映射关系-->
<resultMap id="EmpAndDeptByStepTwoResultMap" type="Dept">
	<id property="did" column="did"></id>
	<result property="deptName" column="dept_name"></result>
</resultMap>
<!--Dept getEmpAndDeptByStepTwo(@Param("did") Integer did);-->
<select id="getEmpAndDeptByStepTwo" resultMap="EmpAndDeptByStepTwoResultMap">
	select * from t_dept where did = #{did}
</select>

One-to-many mapping processing

public class Dept {
    
    
    private Integer did;
    private String deptName;
    private List<Emp> emps;
	//...构造器、get、set方法等
}

collection

  • collection: used to handle one-to-many mapping relationships
  • ofType: Indicates the type of data stored in the collection that this attribute corresponds to
<resultMap id="DeptAndEmpResultMap" type="Dept">
	<id property="did" column="did"></id>
	<result property="deptName" column="dept_name"></result>
	<collection property="emps" ofType="Emp">
		<id property="eid" column="eid"></id>
		<result property="empName" column="emp_name"></result>
		<result property="age" column="age"></result>
		<result property="sex" column="sex"></result>
		<result property="email" column="email"></result>
	</collection>
</resultMap>
<!--Dept getDeptAndEmp(@Param("did") Integer did);-->
<select id="getDeptAndEmp" resultMap="DeptAndEmpResultMap">
	select * from t_dept left join t_emp on t_dept.did = t_emp.did where t_dept.did = #{did}
</select>

Step by step query

1. Query department information
/**
 * 通过分步查询,查询部门及对应的所有员工信息
 * 分步查询第一步:查询部门信息
 * @param did 
 * @return com.atguigu.mybatis.pojo.Dept
 * @date 2022/2/27 22:04
 */
Dept getDeptAndEmpByStepOne(@Param("did") Integer did);
<resultMap id="DeptAndEmpByStepOneResultMap" type="Dept">
	<id property="did" column="did"></id>
	<result property="deptName" column="dept_name"></result>
	<collection property="emps"
				select="com.atguigu.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo"
				column="did"></collection>
</resultMap>
<!--Dept getDeptAndEmpByStepOne(@Param("did") Integer did);-->
<select id="getDeptAndEmpByStepOne" resultMap="DeptAndEmpByStepOneResultMap">
	select * from t_dept where did = #{did}
</select>
2. Query all employees in the department based on department ID
/**
 * 通过分步查询,查询部门及对应的所有员工信息
 * 分步查询第二步:根据部门id查询部门中的所有员工
 * @param did
 * @return java.util.List<com.atguigu.mybatis.pojo.Emp>
 * @date 2022/2/27 22:10
 */
List<Emp> getDeptAndEmpByStepTwo(@Param("did") Integer did);
<!--List<Emp> getDeptAndEmpByStepTwo(@Param("did") Integer did);-->
<select id="getDeptAndEmpByStepTwo" resultType="Emp">
	select * from t_emp where did = #{did}
</select>

Lazy loading

  • Advantages of step-by-step query: Lazy loading can be achieved, but global configuration information must be set in the core configuration file:
    • lazyLoadingEnabled: global switch for lazy loading. When enabled, all associated objects will be loaded lazily
    • aggressiveLazyLoading: When turned on, any method call will load all properties of the object. Otherwise, each property is loaded on demand
  • At this time, on-demand loading can be achieved. Whatever data is obtained, only the corresponding SQL will be executed. At this time, you can set whether the current step-by-step query uses lazy loading through the fetchType attribute in association and collection, fetchType="lazy (lazy loading) | eager (immediate loading)"
<settings>
	<!--开启延迟加载-->
	<setting name="lazyLoadingEnabled" value="true"/>
</settings>
@Test
public void getEmpAndDeptByStepOne() {
    
    
	SqlSession sqlSession = SqlSessionUtils.getSqlSession();
	EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
	Emp emp = mapper.getEmpAndDeptByStepOne(1);
	System.out.println(emp.getEmpName());
}
  • Turn off lazy loading and both SQL statements are run.

  • Insert image description here

  • Turn on lazy loading and only run the SQL statement to obtain emp
    Insert image description here

@Test
public void getEmpAndDeptByStepOne() {
    
    
	SqlSession sqlSession = SqlSessionUtils.getSqlSession();
	EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
	Emp emp = mapper.getEmpAndDeptByStepOne(1);
	System.out.println(emp.getEmpName());
	System.out.println("----------------");
	System.out.println(emp.getDept());
}
  • After it is turned on, the corresponding SQL statement will be called only when querying dept.

  • Insert image description here

  • fetchType: When global lazy loading is enabled, you can manually control the effect of lazy loading through this attribute, fetchType="lazy (lazy loading)|eager (immediate loading)"

    <resultMap id="empAndDeptByStepResultMap" type="Emp">
    	<id property="eid" column="eid"></id>
    	<result property="empName" column="emp_name"></result>
    	<result property="age" column="age"></result>
    	<result property="sex" column="sex"></result>
    	<result property="email" column="email"></result>
    	<association property="dept"
    				 select="com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
    				 column="did"
    				 fetchType="lazy"></association>
    </resultMap>
    

Dynamic SQL

  • The dynamic SQL technology of the Mybatis framework is a function that dynamically assembles SQL statements according to specific conditions. The purpose of its existence is to solve the pain points when splicing SQL statement strings.

if

  • The if tag can be judged by the expression of the test attribute (that is, the passed data). If the result of the expression is true, the content in the tag will be executed; otherwise, the content in the tag will not be executed.
  • Add a constant establishment condition after where1=1
    • This constant establishment condition will not affect the query results.
    • This1=1 can be used to spliceand statements, for example: when empName is null
      • If the constant establishment condition is not added, the SQL statement is select * from t_emp where and age = ? and sex = ? and email = ?. At this time, where will be used together with and , the SQL statement will report an error
      • If a constant condition is added, the SQL statement isselect * from t_emp where 1= 1 and age = ? and sex = ? and email = ?, and no error will be reported
<!--List<Emp> getEmpByCondition(Emp emp);-->
<select id="getEmpByCondition" resultType="Emp">
	select * from t_emp where 1=1
	<if test="empName != null and empName !=''">
		and emp_name = #{empName}
	</if>
	<if test="age != null and age !=''">
		and age = #{age}
	</if>
	<if test="sex != null and sex !=''">
		and sex = #{sex}
	</if>
	<if test="email != null and email !=''">
		and email = #{email}
	</if>
</select>

where

  • Where and if are generally used together:
    • If none of the if conditions in the where tag are satisfied, the where tag has no function, that is, the where keyword will not be added.
    • If the if condition in the where tag is met, the where tag will automatically add the where keyword, and remove the redundant and/or at the front of the condition.
<!--List<Emp> getEmpByCondition(Emp emp);-->
<select id="getEmpByCondition" resultType="Emp">
	select * from t_emp
	<where>
		<if test="empName != null and empName !=''">
			emp_name = #{empName}
		</if>
		<if test="age != null and age !=''">
			and age = #{age}
		</if>
		<if test="sex != null and sex !=''">
			and sex = #{sex}
		</if>
		<if test="email != null and email !=''">
			and email = #{email}
		</if>
	</where>
</select>
  • Note: The where tag cannot remove the redundant and/or after the condition.

    <!--这种用法是错误的,只能去掉条件前面的and/or,条件后面的不行-->
    <if test="empName != null and empName !=''">
    emp_name = #{empName} and
    </if>
    <if test="age != null and age !=''">
    	age = #{age}
    </if>
    

trim

  • trim is used to remove or add content in tags
  • Common properties
    • prefix: Add some content in front of the content in the trim tag
    • suffix: Add some content after the content in the trim tag
    • prefixOverrides: Remove certain content in front of the content in the trim tag
    • suffixOverrides: Remove certain content after the content in the trim tag
  • If none of the tags in trim meet the conditions, the trim tag will have no effect, that is, onlyselect * from t_emp
<!--List<Emp> getEmpByCondition(Emp emp);-->
<select id="getEmpByCondition" resultType="Emp">
	select * from t_emp
	<trim prefix="where" suffixOverrides="and|or">
		<if test="empName != null and empName !=''">
			emp_name = #{empName} and
		</if>
		<if test="age != null and age !=''">
			age = #{age} and
		</if>
		<if test="sex != null and sex !=''">
			sex = #{sex} or
		</if>
		<if test="email != null and email !=''">
			email = #{email}
		</if>
	</trim>
</select>
//测试类
@Test
public void getEmpByCondition() {
    
    
	SqlSession sqlSession = SqlSessionUtils.getSqlSession();
	DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
	List<Emp> emps= mapper.getEmpByCondition(new Emp(null, "张三", null, null, null, null));
	System.out.println(emps);
}

Insert image description here

choose、when、otherwise

  • choose、when、otherwiseEquivalent toif...else if..else
  • when there must be at least one, otherwise there must be at most one
<select id="getEmpByChoose" resultType="Emp">
	select * from t_emp
	<where>
		<choose>
			<when test="empName != null and empName != ''">
				emp_name = #{empName}
			</when>
			<when test="age != null and age != ''">
				age = #{age}
			</when>
			<when test="sex != null and sex != ''">
				sex = #{sex}
			</when>
			<when test="email != null and email != ''">
				email = #{email}
			</when>
			<otherwise>
				did = 1
			</otherwise>
		</choose>
	</where>
</select>
@Test
public void getEmpByChoose() {
    
    
	SqlSession sqlSession = SqlSessionUtils.getSqlSession();
	DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
	List<Emp> emps = mapper.getEmpByChoose(new Emp(null, "张三", 23, "男", "[email protected]", null));
	System.out.println(emps);
}

Insert image description here

  • is equivalent toif a else if b else if c else d, only one of them will be executed

foreach

  • Attributes:

    • collection: Set the array or collection to be looped
    • item: represents each data in the collection or array
    • separator: Set the separator between loop bodies. There is a space before and after the separator by default, such as,
    • open: Set the start character of the content in the foreach tag
    • close: Set the end character of the content in the foreach tag
  • batch deletion

    <!--int deleteMoreByArray(Integer[] eids);-->
    <delete id="deleteMoreByArray">
    	delete from t_emp where eid in
    	<foreach collection="eids" item="eid" separator="," open="(" close=")">
    		#{eid}
    	</foreach>
    </delete>
    
    @Test
    public void deleteMoreByArray() {
          
          
    	SqlSession sqlSession = SqlSessionUtils.getSqlSession();
    	DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
    	int result = mapper.deleteMoreByArray(new Integer[]{
          
          6, 7, 8, 9});
    	System.out.println(result);
    }
    

    Insert image description here

  • Add in batches

    <!--int insertMoreByList(@Param("emps") List<Emp> emps);-->
    <insert id="insertMoreByList">
    	insert into t_emp values
    	<foreach collection="emps" item="emp" separator=",">
    		(null,#{emp.empName},#{emp.age},#{emp.sex},#{emp.email},null)
    	</foreach>
    </insert>
    
    @Test
    public void insertMoreByList() {
          
          
    	SqlSession sqlSession = SqlSessionUtils.getSqlSession();
    	DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
    	Emp emp1 = new Emp(null,"a",1,"男","[email protected]",null);
    	Emp emp2 = new Emp(null,"b",1,"男","[email protected]",null);
    	Emp emp3 = new Emp(null,"c",1,"男","[email protected]",null);
    	List<Emp> emps = Arrays.asList(emp1, emp2, emp3);
    	int result = mapper.insertMoreByList(emps);
    	System.out.println(result);
    }
    

    Insert image description here

SQL fragment

  • SQL fragment can record a public SQL fragment and introduce it through the include tag where it is used.
  • Declare sql fragment:<sql>Tag
<sql id="empColumns">eid,emp_name,age,sex,email</sql>
  • Quote sql fragment:<include>tag
<!--List<Emp> getEmpByCondition(Emp emp);-->
<select id="getEmpByCondition" resultType="Emp">
	select <include refid="empColumns"></include> from t_emp
</select>

MyBatis cache

MyBatis's first-level cache

  • The first-level cache is at the SqlSession level. Data queried through the same SqlSession will be cached. The next time you query the same data, it will be obtained directly from the cache and will not be revisited from the database.

  • Four situations that invalidate the first-level cache:

    1. Different SqlSession corresponds to different first-level cache
    2. The same SqlSession but different query conditions
    3. Any addition, deletion or modification operation was performed during the two queries of the same SqlSession.
    4. The cache was manually cleared during two queries on the same SqlSession.

MyBatis second-level cache

  • The second-level cache is at the SqlSessionFactory level. The results of SqlSession queries created through the same SqlSessionFactory will be cached; if the same query statement is executed again thereafter, the results will be obtained from the cache.

  • Conditions for enabling second-level cache

    1. In the core configuration file, set the global configuration attribute cacheEnabled="true". The default is true and does not need to be set.
    2. Set labels in mapping files
    3. The second level cache must be valid after the SqlSession is closed or committed
    4. The entity class type converted by the query data must implement the serialization interface
  • Invalidation of the second-level cache: Any additions, deletions, and modifications performed between two queries will invalidate both the first-level and second-level caches at the same time.

Second level cache related configuration

  • The cache tag added in the mapper configuration file can set some properties
  • eviction attribute: cache recycling strategy
    • LRU (Least Recently Used) – Least Recently Used: Remove objects that have not been used for the longest time.
    • FIFO (First in First out) – Remove objects in the order they enter the cache.
    • SOFT – Soft Reference: Removes objects based on garbage collector status and soft reference rules.
    • WEAK – Weak References: More aggressively remove objects based on garbage collector state and weak reference rules.
    • The default is LRU
  • flushInterval attribute: refresh interval, in milliseconds
    • The default is not set, that is, there is no refresh interval. The cache is only refreshed when statements (add, delete, modify) are called.
  • size attribute: number of references, positive integer
    • Represents the maximum number of objects that the cache can store. If it is too large, it may cause memory overflow.
  • readOnly attribute: read-only, true/false
    • true: read-only cache; will return the same instance of the cache object to all callers. Therefore these objects cannot be modified. This provides important performance advantages.
    • false: Read and write cache; will return a copy of the cache object (via serialization). This is slower, but safer, so defaults to false

MyBatis cache query order

  • Query the second-level cache first, because there may be data in the second-level cache that has been found by other programs and can be used directly.
  • If there is no hit in the second-level cache, query the first-level cache again.
  • If there is no hit in the first-level cache, query the database
  • After SqlSession is closed, the data in the first-level cache will be written to the second-level cache.

Integrate third-party cache EHCache (understand)

Add dependencies

<!-- Mybatis EHCache整合包 -->
<dependency>
	<groupId>org.mybatis.caches</groupId>
	<artifactId>mybatis-ehcache</artifactId>
	<version>1.2.1</version>
</dependency>
<!-- slf4j日志门面的一个具体实现 -->
<dependency>
	<groupId>ch.qos.logback</groupId>
	<artifactId>logback-classic</artifactId>
	<version>1.2.3</version>
</dependency>

The functions of each jar package

jar package name effect
mybatis-ehcache Integration package for Mybatis and EHCache
ehcache EHCache core package
slf4j-api SLF4J Log Portal Bundle
logback-classic Support a specific implementation of the SLF4J facade interface

Create the EHCache configuration file ehcache.xml

  • The name must be calledehcache.xml
<?xml version="1.0" encoding="utf-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    <!-- 磁盘保存路径 -->
    <diskStore path="D:\atguigu\ehcache"/>
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="true"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>

Set the type of second-level cache

  • Set the second-level cache type in the xxxMapper.xml file
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

Add logback log

  • When SLF4J exists, log4j as a simple log will be invalid. At this time, we need to use the specific implementation of SLF4J logback to print the log. Create a logback configuration filelogback.xml, the name is fixed and cannot be changed
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
    <!-- 指定日志输出的位置 -->
    <appender name="STDOUT"
              class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!-- 日志输出的格式 -->
            <!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 -->
            <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern>
        </encoder>
    </appender>
    <!-- 设置全局日志级别。日志级别按顺序分别是:DEBUG、INFO、WARN、ERROR -->
    <!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
    <root level="DEBUG">
        <!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
        <appender-ref ref="STDOUT" />
    </root>
    <!-- 根据特殊需求指定局部日志级别 -->
    <logger name="com.atguigu.crowd.mapper" level="DEBUG"/>
</configuration>

EHCache configuration file description

attribute name Is it necessary effect
maxElementsInMemory yes The maximum number of elements cached in memory
maxElementsOnDisk yes The maximum number of elements cached on disk, if 0 means infinity
eternal yes Sets whether cached elements never expire. If it is true, the cached data is always valid. If it is false, it must be judged based on timeToIdleSeconds and timeToLiveSeconds.
overflowToDisk yes Set whether to cache expired elements to disk when the memory buffer overflows
timeToIdleSeconds no When the time between two accesses to the data cached in EhCache exceeds the value of the timeToIdleSeconds attribute, the data will be deleted. The default value is 0, which means that the idle time is infinite.
timeToLiveSeconds no The effective lifetime of the cache element, the default is 0. That is, the element survival time is infinite.
diskSpoolBufferSizeMB no The cache area size of DiskStore (disk cache). The default is 30MB. Each Cache should have its own buffer
diskPersistent no Whether to enable the disk to save data in EhCache when the VM is restarted. The default is false.
diskExpiryThreadIntervalSeconds no The disk cache cleaning thread running interval, the default is 120 seconds. Every 120s, the corresponding thread will clean the data in EhCache.
memoryStoreEvictionPolicy no When the memory cache reaches the maximum size and a new element is added, the strategy of removing elements from the cache is used. The default is LRU (least recently used), the options are LFU (least frequently used) and FIFO (first in first out)

Reverse engineering of MyBatis

  • Forward engineering: First create Java entity classes, and the framework is responsible for generating database tables based on the entity classes. Hibernate supports forward engineering
  • Reverse engineering: Create a database table first, and the framework is responsible for reversely generating the following resources based on the database table:
    • Java entity class
    • Mapper interface
    • Mapper mapping file

Steps to Create a Reverse Engineering

Add dependencies and plugins

<dependencies>
	<!-- MyBatis核心依赖包 -->
	<dependency>
		<groupId>org.mybatis</groupId>
		<artifactId>mybatis</artifactId>
		<version>3.5.9</version>
	</dependency>
	<!-- junit测试 -->
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.13.2</version>
		<scope>test</scope>
	</dependency>
	<!-- MySQL驱动 -->
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>8.0.27</version>
	</dependency>
	<!-- log4j日志 -->
	<dependency>
		<groupId>log4j</groupId>
		<artifactId>log4j</artifactId>
		<version>1.2.17</version>
	</dependency>
</dependencies>
<!-- 控制Maven在构建过程中相关配置 -->
<build>
	<!-- 构建过程中用到的插件 -->
	<plugins>
		<!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
		<plugin>
			<groupId>org.mybatis.generator</groupId>
			<artifactId>mybatis-generator-maven-plugin</artifactId>
			<version>1.3.0</version>
			<!-- 插件的依赖 -->
			<dependencies>
				<!-- 逆向工程的核心依赖 -->
				<dependency>
					<groupId>org.mybatis.generator</groupId>
					<artifactId>mybatis-generator-core</artifactId>
					<version>1.3.2</version>
				</dependency>
				<!-- 数据库连接池 -->
				<dependency>
					<groupId>com.mchange</groupId>
					<artifactId>c3p0</artifactId>
					<version>0.9.2</version>
				</dependency>
				<!-- MySQL驱动 -->
				<dependency>
					<groupId>mysql</groupId>
					<artifactId>mysql-connector-java</artifactId>
					<version>8.0.27</version>
				</dependency>
			</dependencies>
		</plugin>
	</plugins>
</build>

Create the core configuration file of MyBatis

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <properties resource="jdbc.properties"/>
    <typeAliases>
        <package name=""/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <package name=""/>
    </mappers>
</configuration>

Create configuration files for reverse engineering

  • The file name must be:generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!--
    targetRuntime: 执行生成的逆向工程的版本
    MyBatis3Simple: 生成基本的CRUD(清新简洁版)
    MyBatis3: 生成带条件的CRUD(奢华尊享版)
    -->
    <context id="DB2Tables" targetRuntime="MyBatis3Simple">
        <!-- 数据库的连接信息 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/mybatis"
                        userId="root"
                        password="123456">
        </jdbcConnection>
        <!-- javaBean的生成策略-->
        <javaModelGenerator targetPackage="com.atguigu.mybatis.pojo" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- SQL映射文件的生成策略 -->
        <sqlMapGenerator targetPackage="com.atguigu.mybatis.mapper"
                         targetProject=".\src\main\resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        <!-- Mapper接口的生成策略 -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.atguigu.mybatis.mapper" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        <!-- 逆向分析的表 -->
        <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
        <!-- domainObjectName属性指定生成出来的实体类的类名 -->
        <table tableName="t_emp" domainObjectName="Emp"/>
        <table tableName="t_dept" domainObjectName="Dept"/>
    </context>
</generatorConfiguration>

Execute the generate target of the MBG plug-in

  • Insert image description here

  • If an error occurs:Exception getting JDBC Driver, it may be that the database driver configuration is wrong in pom.xml

    • Driver in dependency

    • Insert image description here

    • Driver in mybatis-generator-maven-plugin plug-in

    • Insert image description here

    • The driver version of both should be the same

  • Results of the

  • Insert image description here

QBC

Inquire

  • selectByExample: To query by condition, you need to pass in an example object or null; if you pass in a null, it means there is no condition, that is, all data is queried.
  • example.createCriteria().xxx: Create a condition object and add a query to SQL through the andXXX method. There is an and relationship between each condition.
  • example.or().xxx: Combine the previously added conditions with other conditions through or
    Insert image description here
@Test public void testMBG() throws IOException {
    
    
	InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
	SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
	SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
	SqlSession sqlSession = sqlSessionFactory.openSession(true);
	EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
	EmpExample example = new EmpExample();
	//名字为张三,且年龄大于等于20
	example.createCriteria().andEmpNameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);
	//或者did不为空
	example.or().andDidIsNotNull();
	List<Emp> emps = mapper.selectByExample(example);
	emps.forEach(System.out::println);
}

Insert image description here

Additions and changes

  • updateByPrimaryKey: Modify data through the primary key. If a certain value is null, the corresponding field will also be changed to null.

  • updateByPrimaryKeySelective(): Selective data modification through primary key. If a value is null, this field will not be modified.

Pagination plugin

Steps to use the paging plug-in

Add dependencies

<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
	<groupId>com.github.pagehelper</groupId>
	<artifactId>pagehelper</artifactId>
	<version>5.2.0</version>
</dependency>

Configure paging plugin

  • Configure the plug-in in the core configuration file of MyBatis (mybatis-config.xml)
  • Insert image description here
<plugins>
	<!--设置分页插件-->
	<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

Use of paging plug-in

Turn on paging

  • Use before query functionPageHelper.startPage(int pageNum, int pageSize) to enable paging function
    • pageNum: The page number of the current page
    • pageSize: Number of items displayed on each page
@Test
public void testPageHelper() throws IOException {
    
    
	InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
	SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
	SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
	SqlSession sqlSession = sqlSessionFactory.openSession(true);
	EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
	//访问第一页,每页四条数据
	PageHelper.startPage(1,4);
	List<Emp> emps = mapper.selectByExample(null);
	emps.forEach(System.out::println);
}

Insert image description here

Pagination related data

Method 1: Direct output
@Test
public void testPageHelper() throws IOException {
    
    
	InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
	SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
	SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
	SqlSession sqlSession = sqlSessionFactory.openSession(true);
	EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
	//访问第一页,每页四条数据
	Page<Object> page = PageHelper.startPage(1, 4);
	List<Emp> emps = mapper.selectByExample(null);
	//在查询到List集合后,打印分页数据
	System.out.println(page);
}
  • Pagination related data:

    Page{count=true, pageNum=1, pageSize=4, startRow=0, endRow=4, total=8, pages=2, reasonable=false, pageSizeZero=false}[Emp{eid=1, empName='admin', age=22, sex='男', email='[email protected]', did=3}, Emp{eid=2, empName='admin2', age=22, sex='男', email='[email protected]', did=3}, Emp{eid=3, empName='王五', age=12, sex='女', email='[email protected]', did=3}, Emp{eid=4, empName='赵六', age=32, sex='男', email='[email protected]', did=1}]
    
Method 2 uses PageInfo
  • After querying to obtain the list collection, usePageInfo<T> pageInfo = new PageInfo<>(List<T> list, intnavigatePages) to obtain paging related data
    • list: data after paging
    • navigatePages: the number of pages for navigation paging
@Test
public void testPageHelper() throws IOException {
    
    
	InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
	SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
	SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
	SqlSession sqlSession = sqlSessionFactory.openSession(true);
	EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
	PageHelper.startPage(1, 4);
	List<Emp> emps = mapper.selectByExample(null);
	PageInfo<Emp> page = new PageInfo<>(emps,5);
	System.out.println(page);
}
  • Pagination related data:

    PageInfo{
    pageNum=1, pageSize=4, size=4, startRow=1, endRow=4, total=8, pages=2, 
    list=Page{count=true, pageNum=1, pageSize=4, startRow=0, endRow=4, total=8, pages=2, reasonable=false, pageSizeZero=false}[Emp{eid=1, empName='admin', age=22, sex='男', email='[email protected]', did=3}, Emp{eid=2, empName='admin2', age=22, sex='男', email='[email protected]', did=3}, Emp{eid=3, empName='王五', age=12, sex='女', email='[email protected]', did=3}, Emp{eid=4, empName='赵六', age=32, sex='男', email='[email protected]', did=1}], 
    prePage=0, nextPage=2, isFirstPage=true, isLastPage=false, hasPreviousPage=false, hasNextPage=true, navigatePages=5, navigateFirstPage=1, navigateLastPage=2, navigatepageNums=[1, 2]}
    
  • The data in the list is equivalent to the page data directly output in method one.

Commonly used data:
  • pageNum: The page number of the current page
  • pageSize: Number of items displayed on each page
  • size: the actual number of items displayed on the current page
  • total: total number of records
  • pages: total number of pages
  • prePage: page number of the previous page
  • nextPage: The page number of the next page
  • isFirstPage/isLastPage: whether it is the first page/last page
  • hasPreviousPage/hasNextPage: Whether there is a previous page/next page
  • navigatePages: the number of pages for navigation paging
  • navigatepageNums: page number of navigation paging, [1,2,3,4,5]

Guess you like

Origin blog.csdn.net/Coastlise/article/details/134888202