introduce
- MyBatis is an excellent persistence framework;
- It supports custom SQL, stored procedures, and advanced mappings. MyBatis eliminates almost all of the JDBC code and the work of setting parameters and getting result sets. MyBatis configures and maps primitive types, interfaces, and Java POJOs to records in the database using simple XML or annotations.
The sample
Set up the environment
<! -- Import dependencies -->
<dependencies>
<! - mysqlq driver - >
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.12</version>
</dependency>
<! --mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
</dependencies>
Copy the code
Create a module
Write myBatis core configuration file myBatis -config.xml
<! DOCTYPEconfiguration
PUBLIC "- / / mybatis.org//DTD Config / 3.0 / EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<! --configuration core configuration file -->
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis? userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
</configuration>
Copy the code
Write the MyBatis utility class
//sqlSessionFactory --> sqlSession
public class MybatisUtils {
static SqlSessionFactory sqlSessionFactory = null;
static {
try {
// Use Mybatis to obtain the sqlSessionFactory object
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch(IOException e) { e.printStackTrace(); }}// Since we have an SqlSessionFactory, as the name implies, we can get an instance of SqlSession from it.
// SqlSession provides all the methods needed to execute SQL commands in the database.
public static SqlSession getSqlSession(a){
returnsqlSessionFactory.openSession(); }}Copy the code
Write the code
The package name in the namespace must be the same as that of the Dao/Mapper interface
- Id: indicates the method name in the namespace.
- ResultType: return value of Sql statement execution.
- ParameterType: indicates the parameterType.
public interface UserDao {
public List<User> getUserList(a); } <? xml version="1.0" encoding="UTF-8"? > <! DOCTYPE mapper PUBLIC"- / / mybatis.org//DTD Mapper / 3.0 / EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <! --namespace= Bind a Dao/Mapper interface --> < Mapper namespace="com.zwt.dao.UserDao">
<select id="getUserList" resultType="com.kuang.pojo.User">
select * from USER
</select>
</mapper>
@Test
public void test(a){
//1. Obtain the SqlSession object
SqlSession sqlSession = MybatisUtils.getSqlSession();
/ / 2. Execute SQL
// Method 1: getMapper
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userList = userDao.getUserList();
for (User user : userList) {
System.out.println(user);
}
/ / close the sqlSession
sqlSession.close();
}
Copy the code
CURD
Note: Add, delete, and check must be committed to the transaction:
sqlSession.commit();
Copy the code
Universal Map
Assuming that our entity class or database has too many tables, fields, or parameters, we should consider using Map!
// Insert user with universal Map
public void addUser2(Map<String,Object> map); <! <insert id= <insert id= <insert id= <insert id="addUser2" parameterType="map">
insert into user (id,name,password) values (#{userid},#{username},#{userpassword})
</insert>
Copy the code
Map pass parameter, directly in SQL extract key can be! 【 parameter = “map”
Object pass parameters, directly in SQL to take out the object properties can be! 【 parameter = “Object”
In the case of only one basic type parameter, it can be fetched directly in SQL
Multiple parameters are mapped, or annotated!
Configure the parsing
- mybatis-config.xml
- The Mybatis configuration file contains Settings and attributes that deeply affect the behavior of Mybatis.
Configuration properties Settings typeAliases typeHandlers objectFactory plugins Environments Environment variables transactionManager dataSource databaseIdProvider MappersCopy the code
Environment configuration
MyBatis can be configured for a variety of environments
Keep in mind, though: although multiple environments can be configured, only one environment can be selected per SqlSessionFactory instance
Learn how to configure multiple running environments!
MyBatis default transaction manager is JDBC, connection pool: POOLED
The attribute properties
The reference configuration file can be implemented using the properties property
These properties can be configured externally and can be dynamically replaced.
You can configure these properties either in a typical Java properties file or in a child element of the Properties element. 【 the poperties 】
TypeAliases typeAliases
- A type alias can set an abbreviated name for a Java type. It is only used for XML configuration.
- Intended to reduce redundant fully qualified class name writing.
<! You can alias an entity class -->
<typeAliases>
<typeAlias type="com.zwt.pojo.User" alias="User"/>
</typeAliases>
Copy the code
<typeAliases>
<package name="com.kuang.pojo"/>
</typeAliases>
@Alias("author")
public class Author {... }Copy the code
Other configuration
- typeHandlers
- ObjectFactory = objectFactory
- The plugins plugin
- mybatis-generator-core
- mybatis-plus
- General mapper
Mapper mappers
MapperRegistry: register binding to our Mapper files;
Method 1: [Recommended use]
<! -- Each mapper. XML needs to be registered in the MyBatis core configuration file -->
<mappers>
<mapper resource="com/zwt/dao/UserMapper.xml"/>
</mappers>
Copy the code
Method 2: Register using class file binding
<! -- Each mapper. XML needs to be registered in the MyBatis core configuration file -->
<mappers>
<mapper class="com.zwt.dao.UserMapper"/>
</mappers>Note: The interface and its Mapper profile must have the same name. The interface and its Mapper profile must be in the same packageCopy the code
Method 3: Use package scan for injection
<mappers>
<package name="com.kuang.dao"/>
</mappers>
Copy the code
Scope and lifecycle
SqlSessionFactoryBuilder:
- Once the SqlSessionFactory is created, it is no longer needed
- A local variable
SqlSessionFactory:
- To put it bluntly: database connection pooling
- Once created, the qlSessionFactory should exist for the duration of the application, and there is no reason to discard it or recreate an instance
- Therefore, the best scope for SqlSessionFactory is the application scope (ApplocationContext).
- The simplest is to use the singleton or static singleton pattern.
SqlSession:
- A request to connect to the connection pool
- Instances of SqlSession are not thread-safe and therefore cannot be shared, so its best scope is the request or method scope.
- After use, need to close quickly, otherwise the resource is occupied!
paging
Paging is used to reduce the amount of data processed
Paging with Limit
/ / paging
List<User> getUserByLimit(Map<String,Integer> map); <! <select id="getUserByLimit" parameterType="map" resultMap="UserMap">
select * from user limit #{startIndex},#{pageSize}
</select>
@Test
public void getUserByLimit(a){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("startIndex".1);
map.put("pageSize".2);
List<User> list = mapper.getUserByLimit(map);
for(User user : list) { System.out.println(user); }}Copy the code
RowBounds paging
/ / page 2
List<User> getUserByRowBounds(a); <! -- Paging query2-->
<select id="getUserByRowBounds">
select * from user limit #{startIndex},#{pageSize}
</select>
public void getUserByRowBounds(a){
SqlSession sqlSession = MybatisUtils.getSqlSession();
/ / RowBounds implementation
RowBounds rowBounds = new RowBounds(1.2);
// Implement paging at the Java code level
List<User> userList = sqlSession.selectList("com.zwt.dao.UserMapper.getUserByRowBounds".null, rowBounds);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
Copy the code
Paging plug-in
Annotations to develop
// Annotations are implemented on the interface
@Select("select * from user")
List<User> getUsers(a);
// Interfaces need to be bound in the core configuration file
<mappers>
<mapper class="com.zwt.dao.UserMapper"/>
</mappers>
Copy the code
Essence: Reflection mechanism implementation
Bottom layer: dynamic proxy
MyBatis detailed execution process
Annotations CURD
// The method has multiple arguments. All arguments must be preceded by @param ("id") annotations
@Delete("delete from user where id = ${uid}")
int deleteUser(@Param("uid") int id);
Copy the code
About @param () annotations
- Parameter of basic type or String type, need to add
- Reference types do not need to be added
- If there is only one basic type, you can ignore it, but it is recommended that everyone add it
- What we’re referring to in SQL is the name of the property that we set here in @param ()
Many-to-one and many-to-many
Multiple students one teacher;
For one more
alter table student ADD CONSTRAINT fk_tid foreign key (tid) references teacher(id)
Copy the code
Test environment construction:
- Import lombok
- Create an entity class Teacher,Student
- Example Establish a Mapper interface
- Create the mapper.xml file
- Bind and register our Mapper interface or file in the core profile.
- Tests whether the query succeeds
@Data
public class Student {
private int id;
private String name;
private int tid;
}
@Data
public class Student {
private int id;
private String name;
private int tid;
}
Copy the code
// Follow the query nesting process<! - ideas:1.Query all student information2.Select * from student where id= id; select * from student where id= id; select * from student where id= id"getStudent" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="student">
<result property="id" column="id"/>
<result property="name" column="name"/ > <! -- Complex property, we need to separate out the object: association collection: collection--> <collection property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="teacher">
select * from teacher where id = #{id}
</select>
// The result is nested<! Select id=. Select id="getStudent2" resultMap="StudentTeacher2"> select s.id sid , s.name sname, t.name tname from student s,teacher t where s.tid=t.id </select> <! > <resultMap id= <resultMap id= <resultMap id= <resultMap id="StudentTeacher2" type="student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="teacher">
<result property="name" column="tname"></result>
</association>
</resultMap>
Copy the code
- Subqueries (nested by query)
- Join table query (nested by results)
More than a pair of
<! Select id= (select id= (select id= (select id= (select id=)))"getTeacher" resultMap="StudentTeacher">
SELECT s.id sid, s.name sname,t.name tname,t.id tid FROM student s, teacher t
WHERE s.tid = t.id AND tid = #{tid}
</select>
<resultMap id="StudentTeacher" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/ > <! -- Complex properties that we need to handle the object separately: Association collection: Collection javaType=""Specify the type of the property! For generic information in collection, we use ofType --> <collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
Copy the code
summary
- Association-association [many-to-one]
- A collection of one to many
- javaType & ofType
- JavaType is used to specify the type in an entity class
- OfType specifies poJO types that map to lists or collections, and constraint types in generics
Dynamic SQL
What is dynamic SQL: Dynamic SQL is the generation of different SQL statements based on different conditions
So dynamic SQL is essentially SQL statements, but we can execute a logical code at the SQL level
For example IF
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from blog
<where>
<if test="title! =null">
and title = #{title}
</if>
<if test="author! =null">
and author = #{author}
</if>
</where>
</select>
<sql id="if-title-author">
<if test="title! =null">
title = #{title}
</if>
<if test="author! =null">
and author = #{author}
</if>
</sql>
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from blog
<where>
<include refid="if-title-author"></include>
</where>
</select>
Copy the code
Dynamic SQL is in the splicing of SQL statements, we only need to ensure the correctness of the SQL, according to the SQL format, to arrange the combination can be
Advice:
- First write the complete SQL in Mysql, and then modify the corresponding to our dynamic SQL implementation can be general
MyBatis cache
Query: Connects to the database and consumes resources
The result of a query is temporarily stored in a place where it can be fetched directly
When we query the same data again, we go directly to the cache instead of the database
- MyBatis includes a very powerful query cache feature, which can be very convenient to customize and configure the cache, caching can greatly improve the query efficiency.
- MyBatis system defines two levels of cache by default: level-1 cache and level-2 cache
- By default, only level-1 caching is enabled (SqlSession level caching, also known as local caching)
- Level 2 caching needs to be manually enabled and configured. It is namespace-level caching.
- To improve scalability, MyBatis defines the Cache interface. We can define the level 2 Cache by implementing the Cache interface.
Level 1 cache
- Level 1 cache is also called local cache: SqlSession
- Data queried during the same session with the database is placed in the local cache
- In the future, if you need to retrieve the same data, you can retrieve it directly from the cache without having to query the database
@Test
public void test1(a) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUserById(1);
System.out.println(user);
System.out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
User user2 = mapper.getUserById(1);
System.out.println(user2 == user);
}
// Test, when log is enabled, you can see that JDBC is connected only once
Copy the code
Cache invalidation:
- Query different things
- Add, delete, and change operations may change the original data, so the cache must be refreshed
- Query different mapper.xml
- Manually clear the cache (sqlsession.clearcache ();)
The second level cache
-
The level 2 cache is also called the global cache. The level 1 cache scope is too low, so the level 2 cache is born
-
Namespace-based caching, where each namespace corresponds to a level 2 cache
-
Working mechanism
-
A session queries a piece of data, and that data is placed in the level 1 cache of the current session
-
If the session is closed, the level 1 cache for the session is lost. But what we want is for the session to be closed and the data in the level 1 cache to be stored in the level 2 cache
-
The new session queries for information and retrieves the content from the level 2 cache
-
The data queried by each mapper is stored in its own cache (map)
-
Level 1 cache enabled (SqlSession level cache, also known as local cache)
- Level 2 caching needs to be manually enabled and configured. It is namespace-level caching.
- To improve scalability, MyBatis defines the Cache interface. We can define the level 2 Cache by implementing the Cache interface.
Steps:
<! Setting name= <setting name= <setting name= <setting name= <setting name="cacheEnabled" value="true"/ > <! -- Use level 2 cache in current mapper.xml --> <cache eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
Copy the code
Summary:
- As long as the level 2 cache is enabled, it is valid under the same Mapper
- All data will be stored in the level 1 cache
- Only commits to the level 2 cache if the current session commits or if it is closed
Principle of cache
Note:
- UseCache = “true” useCache= “true”
<select id="getUserById" resultType="user" useCache="true">
select * from user where id = #{id}
</select>
Copy the code
Custom cache – Ehcache
Ehcache is a widely used open source Java distributed cache. Mainly for general purpose caches
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.21.</version>
</dependency>
// Specify in mapper to use our ehCache implementation
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
Copy the code