mybatis framework learning record

After studying MyBatis for a week, I have a general understanding of MyBatis. I know that MyBatis is an excellent persistence layer framework. When writing JDBC in the past, we will find a lot of code duplication, bloated and tedious. It's painstaking. Until the emergence of MyBatis, MyBatis avoided almost all JDBC code and manual setting of parameters and getting result sets. MyBatis can use simple XML or annotations to configure and map native information. In a word, there are fewer operations, more tasks, more concise code, and unnecessary operations. I will focus on what I need to pay attention to and what I have stepped on in the article. The article is concise, fast-paced, and the knowledge points proposed need to be digested slowly

Article directory

1.1. Build mybatis environment

1.2.mybatis overall architecture

1.3. Create project

Because it's easy to learn my eclipse tools and common web projects, you can build maven projects, all of which are the same

Remember to change WebRoot\WEB-INF with eclipse. The main purpose is to be compatible with myeclipse, even if myeclipse is used.

1.4. Import dependency

Import mybatis dependency package
Download address:
Extraction code: 0uoc

1.5. Create structure directory

Create the config directory and test directory under java Resources. The config directory is mainly used to put the configuration files sqlMapConfig and log4 log files and database load files , test directory as a test directory, and then create three packages mapper (similar to dao), pojo (similar to bean), utils under src

1.6. Create profile

Create and put it in the config directory, mysql used here


Create the mybatis kernel file sqlMapConfig.xml and put it in the config directory

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-// Config 3.0//EN"
	<!-- Import database connection configuration -->
	<properties resource=""></properties>
	<!-- Define aliases -->
	<!-- <typeAliases> <typeAlias type="" alias="Blog" 
		/> <package name="" /> </typeAliases> -->
	<!-- Define data source -->
	<environments default="test">
		<environment id="test">
			<transactionManager type="JDBC"></transactionManager>
			<dataSource type="POOLED">
				<property name="driver" value="${driver}" />
				<property name="url" value="${url}" />
				<property name="username" value="${username}" />
				<property name="password" value="${password}" />
	<!-- Define mapping file -->
		<!-- <mapper resource="com/gh/mybatis/dao/User.xml" /> -->
		<package name="" />

Note: the mappers label in this can't be forgotten. It can be matched with mapper or package. The main difference between the two is that the former is accurate to a single file, and one more mapping file will be added here. The latter is directly assigned to the whole package. Later mapping files will be created in this package without adding a mapping file

Import log file

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

The whole mybatis environment is set up here

2.1.CRUD operation (using dynamic proxy)

2.2. Creation of database test table

  `uid` int(11) NOT NULL auto_increment,
  `username` varchar(50) default NULL,
  `password` varchar(50) default NULL,
  `status` varchar(10) default NULL,
  PRIMARY KEY  (`uid`)

INSERT INTO USER(uid,username,PASSWORD,STATUS) VALUES(1,'Guo Hang','123456','Y')
INSERT INTO USER(uid,username,PASSWORD,STATUS) VALUES(2,'Guo Degang','123456','Y')
INSERT INTO USER(uid,username,PASSWORD,STATUS) VALUES(3,'Guo Kirin','123456','N')
INSERT INTO USER(uid,username,PASSWORD,STATUS) VALUES(3,'Guo Bao K','123456','N')

2.3. Creation of tool class and entity class

Create pojo class


public class User {
	private int uid;
	private String username;
	private String password;
	private String status;

	public int getUid() {
		return uid;

	public void setUid(int uid) {
		this.uid = uid;

	public String getUsername() {
		return username;

	public void setUsername(String username) {
		this.username = username;

	public String getPassword() {
		return password;

	public void setPassword(String password) {
		this.password = password;

	public String getStatus() {
		return status;

	public void setStatus(String status) {
		this.status = status;

	public User() {
		// TODO Auto-generated constructor stub

	public User(int uid, String username, String password, String status) {
		this.uid = uid;
		this.username = username;
		this.password = password;
		this.status = status;

	public String toString() {
		return "User [uid=" + uid + ", username=" + username + ", password=" + password + ", status=" + status + "]";


Create a mapping file of interface and this class under mapper
Note: the name of the created interface and xml Mapping file must be the same, and it is better to put them under the same package


import java.util.List;


public interface User {

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-// Mapper 3.0//EN"

Import the mybatis tool class to the utils layer. At the beginning, write it several times and then use the tool class to understand and deepen the impression



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

public class MybatisUtils {
	private static SqlSessionFactory sqlSessionFactory = null;

	static {
		try {
			InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");//Import core profile
			sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);//Create a factory
		} catch (IOException e) {
			// TODO Auto-generated catch block

	private MybatisUtils() {

	public static SqlSession getSqlSession() {
		return sqlSessionFactory.openSession();//Get an sqlSession

Create a test package under the test directory and a junit test class under the package


import static org.junit.Assert.*;

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

import javax.websocket.Session;

import org.apache.ibatis.session.SqlSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;


public class MybatisTest {
	private SqlSession sqlsession;

	// Get objects in advance through tool classes
	public void getSqlSession() {
		sqlsession = MybatisUtils.getSqlSession();

	public void getCommint() {


	//Define an intermediate as the output class, in which all fields of all sql query result sets are defined. This method is relatively simple, and there are many in the company

	public void testfindOrdersList() throws Exception {
		User mapper = sqlsession.getMapper(User.class);
		List<QueryOrdersAndUser> findOrdersList = mapper.findOrdersList();
		Iterator<QueryOrdersAndUser> iterator = findOrdersList.iterator();
		while(iterator.hasNext()) {
			QueryOrdersAndUser next =;
			System.out.println(next.getOrder()+"   "+next.getUsername());

After all are created, the directory structure is as follows

Crud a series of operations

2.4.1. First query

Do the following in the User.xml mapping file
Note: as like as two peas in the interface, the id name in the select tag will not be found.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-// Mapper 3.0//EN"
<mapper namespace=""> //namespace: interface location
	<!--*************** CRUD **************** -->
	<select id="findUserByid" parameterType="int"//id: used to map methods in the interface. parameterType: the type of data passed in. Here, the id passed in is int type
		resultType="">//The returned data type. Here you can return the normal type or the object
		select * from user where uid=#{id}//Write sql statement: get value using {}

Configuring methods in an interface

Write test methods


2.4.2. Method without interface

Without using the interface, you can directly use selectOne to get the specific xml method path and pass in parameters instead of defining methods in the user interface

Note: the column name and property name should be the same, otherwise they cannot be mapped. If they are not the same, use resultMap, which will be described later

2.4.3. Fuzzy query

xml file class add select

Add method in interface
Pay attention to the spliced sql statements

2.4.4. Difference between ා and $

Note: if $, the attribute must be value, and only value. In general, we still use#
#{}: placeholder, which can prevent sql injection (single quotation mark '' will be added to the replacement result)
${}: sql splicing symbol (single quotation mark 'will not be added to the replacement result, and like and order by will be used later. There is sql injection problem, which needs to be filtered in the code manually)

2.4.5. Sorting

Sorting is different from other sql queries. First, look at the sql statement select * from user order by {uid} DESC, it seems that there is no problem when you write like this, and it can also run and sort normally in the database. However, in mybatis, it will not report errors, nor sort, and the data will be output as it is. To avoid this problem, you need to use the $symbol to solve this problem , code directly
Add a select tag to the xml file

Add a method to the interface


2.4.6. Multi parameter transfer

The classic example of multiparameter transfer is paging
Be careful:
1. There are three ways to transfer multiple parameters. The first way is to directly assign the value after the sql statement ා, when creating the select tag
eg:select * from user limit #{2},#{2}
2. Use annotation to add Param to the interface. The value of annotation should be consistent with the placeholder parameter of mapper
eg: public List selectUserByPage(@Param("offset") int offset,@Param("pagesize")int pagesize);
3. How to use map
Add the select tag in the xml file, the first way



Second kinds
select * from user limit #{offset},#{pagesize}

Test ibid
Third kinds


2.4.7. Add data

Add data: add an insert tag in the user.xml file, and add it in the normal way
Note: in normal development, we usually want to get the id of the added data after adding a piece of data, so that we can use the selectKey tag

<insert id="insertUser"
		<!-- Add data -->
		<!--Get after adding id -->
		<selectKey resultType="java.lang.Integer" order="AFTER"
			select LAST_INSERT_ID()
		insert into user(username,password) values(#{username},#{password})


public int insertUser(UserBean user);


// Add data
	public void testInsertUser() {
		User usermapper = sqlsession.getMapper(User.class);
		UserBean userBean = new UserBean();
		userBean.setUsername("Zhang San");
		int insertUser = usermapper.insertUser(userBean);

2.4.8. Modify data

Note: when modifying the data, we need to pay attention to the following points: when we modify the data in the normal way, we will find that unless we attach values to all properties, if we modify a single value, other values will become null in the database. For this situation, we have two solutions
1. Query once before adding, but it will access the database twice, which will affect the efficiency. It is not recommended to use
2. Use the dynamic sql tag set, later on!!!



2.4.9. Delete

There is no need to pay attention to the deletion. The deletion is finished according to the normal way. As for batch deletion and batch modification, they are implemented in dynamic sql with foreache, which will be described later


3.1. Dynamic sql

In the following dynamic sql, you can learn more about if, where, foreach and sql segments


The condition in the if tag is equivalent to that the value is not equal to null and the sql in the tag is executed if it is not an empty string. It will automatically add the sql in the if after the sql statement. But note: if the user does not input, then if will not execute. If not, it will execute select statement separately. If not write where 1=1 will lead to incomplete sql statements and errors in incomplete programs. Do we have to write a "where 1=1" every time? The solution is to use the "where" tag, which is used to replace the "where" condition. So the role of "where" is here. The following "where" is just a little more detailed

<select id="selectActiveByAdminName" parameterType="string"
		SELECT * FROM user WHERE 1=1
		<if test="value !=null and value !=''">
			AND username LIKE '%${value}%'


Note: you can understand it as if else. Look at the code

<select id="selectActiveByUserNameOrStyle"
		select * from user where status='Y'
			<when test="username !=null and username!=''">
				and username like #{username}
			<when test="password !=null and password!=''">
				and password like #{password}
				and uid='1'



Note: use set to solve the problem of null modification. With set, you can selectively modify values and other data will not be null

<!-- set Will automatically remove the comma after the statement -->
	<update id="setTest"
		update user 
		<if test="username !=null and username !=''">username=#{username},</if>
		<if test="password !=null and username !=''">password=#{password},</if>
		<if test="status !=null and username !=''">status=#{status}</if>
		where uid=#{uid}



It's no use. I know


Note: it's the end of traversing the batch operation. For example, if you want to delete in batch, you should pay attention to the properties in the collection operation. The collection operation is a collection object, and the item is equivalent to a variable. The following are all splicing characters

<delete id="foreachTest" >
		delete from user where uid in
		<foreach collection="list" item="item" open="(" close=")" separator=",">

testThe most important is sql statement

3.8.sql segment

Its function is to package the repeated code, and use the include reference to the place that needs to be used
For example, when modifying, a lot of parameters will be written every time, so we can use sql fragments to encapsulate it, and use include reference when necessary

4.1. Reverse engineering

What is reverse engineering? It means that all structural directories, configuration files, and the most basic addition, deletion, modification, and query can be generated. That is to say, all the operations we have done before can be generated with one click. It will automatically map the tables in the database to the classes, without writing bean s manually. It's just a bull's-eye

First of all, import dependency is included in the download link given above

Import the reverse engineering line configuration file generator.xml, and remember to put it in java Resources, otherwise it will not be found

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC
        "-// MyBatis Generator Configuration 1.0//EN"
        "" >
	 <context id="context" targetRuntime="MyBatis3">
		<!-- Local database driver jar The full path of a package is renamed its local path when it is used -->
		<!-- <classPathEntry location="D:/software/Mavenrepo/mysql/mysql-connector-java/5.1.44/mysql-connector-java-5.1.44.jar" 
			/> <context id="context" targetRuntime="MyBatis3"> -->
		<!--Define generated java Encoding format of class -->
		<property name="javaFileEncoding" value="UTF-8" />

		<!--suppressAllComments Set totrue No more comments will be generated -->
			<property name="suppressAllComments" value="true" />

		<!-- Database configuration -->
		<jdbcConnection driverClass="com.mysql.jdbc.Driver"
			connectionURL="jdbc:mysql://localhost:3306/springtest" userId="root"
			password="guohang" />

			<property name="forceBigDecimals" value="false" />

		<!-- Location of entity class generation -->
			targetPackage="" targetProject=".\src">
			<property name="trimStrings" value="true" />

		<!-- Mapper.xml Location of files -->
		<sqlMapGenerator targetPackage=""

		<!-- Mapper Location of interface files -->
			targetPackage="" targetProject=".\src"
		<!-- Specify database tables -->
		<table schema="" tableName="user"></table>

Then create a package that contains the reverse engineering execution file


import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.InvalidConfigurationException;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;

public class Generator {
	public static void main(String[] args)
			throws InvalidConfigurationException, IOException, XMLParserException, SQLException, InterruptedException {
		// Paste code from mybatis document
		List<String> warnings = new ArrayList<String>();
		boolean overwrite = true;
		File configFile = new File("generator.xml");
		ConfigurationParser cp = new ConfigurationParser(warnings);
		Configuration config = cp.parseConfiguration(configFile);
		DefaultShellCallback callback = new DefaultShellCallback(overwrite);
		MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);

Note: then you can run it. Just click it once when you run it. It didn't come out because you didn't refresh the directory. If you click it once and add code, it will double and overlap with the number of times you click. Then you have to delete it and execute it again. After you generate it, you will find that the methods in the interface and the sql in the xml are all ready. How to use it to name yourself is over

5.1. L1 cache

Test code

	public void testFindUserByidCacheLevelOne1() {
		User usermapper = sqlsession.getMapper(User.class);
		UserBean findUserByid = usermapper.findUserByid(1);
		System.out.println("Results queried");
		UserBean findUserByid2 = usermapper.findUserByid(1);
		System.out.println("Results queried");
		System.out.println("session Close");

Pay attention to the results. We query twice, but it only executes once. Why? This is the first level cache

First level cache flushed
Test code

	public void testFindUserByidCacheLevelOne2() {
		User usermapper = sqlsession.getMapper(User.class);
		UserBean findUserByid = usermapper.findUserByid(1);
		System.out.println("Results queried");
		UserBean userBean = new UserBean();
		System.out.println("Modification executed");
		UserBean findUserByid2 = usermapper.findUserByid(1);
		System.out.println("Results queried");
		System.out.println("session Close");

As a result, two queries were made

The first level cache is session level cache, which exists by default. When a query is executed within the same session range, if the query is the same, the second query will get the data from the cache. If there are addition, deletion and modification operations between two queries, the SqlSession cache will be automatically cleared, indicating that the next query will execute the sql statement again

5.2. L2 cache

Summary: it is not enabled by default. If the same data query is executed in different session ranges, each query will perform an independent database retrieval process
Enable secondary cache: first add to the configuration file
Then implement the serialization interface. If there are addition, deletion and modification operations between two queries, the SqlSession cache will be automatically cleared, indicating that the next query will execute the sql statement again

6.1. Multi table query

A little bit, too much, I don't want to write. I'm tired. I know that my writing is very rough. It's just for learning. I'll have a look at it. If I want to go beyond the details, I'd like to see: I admire this guy's writing really 666. I'll tell you about the knowledge points in the back. One to one, one to many, many to many, embedded Nested, extended results, constructor mapping, discriminator, delay loading

Published 11 original articles, won praise 5, visited 613
Private letter follow

Tags: Mybatis SQL xml Java

Posted on Tue, 18 Feb 2020 07:06:30 -0500 by Naoa