Mybatis 入門實戰筆記
Mybatis 是一個實現了數據持久化的 ORM 框架,簡單理解就是對 JDBC 進行了封裝。
優點:
- 相比 JDBC 減少了大量代碼量,簡單易學。
- 使用靈活,SQL 語句寫在 XML 裏,從程序代碼中徹底分離,降低了耦合度,便於管理。
- 提供 XML 標籤,支持編寫動態 SQL 語句。
- 提供映射標籤,支持對象與數據庫的 ORM 字段映射關係。
缺點:
- SQL 語句編寫工作量較大,尤其是字段和關聯表多時。
- SQL 語句依賴於數據庫,導致數據庫移植性差,不能隨意更換數據庫。
快速入門實例
環境搭建
新建一個 maven 工程,pom.xml
依賴如下:
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.12</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
創建數據庫表:
CREATE TABLE t_user (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR (20),
PASSWORD VARCHAR (20),
age INT
)
創建表對應的實體類:
@Data
@AllArgsConstructor
public class User {
private Integer id;
private String username;
private String password;
private int age;
}
創建 mybatis 的配置文件 config.xml
,放在 resources 目錄下:
<?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>
<!-- 配置 mybatis 運行環境 -->
<environments default="dev">
<environment id="dev">
<!-- 事務管理 -->
<transactionManager type="JDBC"/>
<!-- 數據源 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis?useUnicode=true&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="sjh2019"/>
</dataSource>
</environment>
</environments>
</configuration>
使用原生接口
Mybatis 框架需要開發者自定義 SQL 語句,寫在 xxxMapper.xml
中,實際開發中會爲每個實體類創建對應的 XML 文件,定義管理該對象數據的 SQL。
創建一個 User 實體類對應的 UserMapper.xml
:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sjh.mapper.UserMapper">
<!-- 添加 -->
<insert id="save" parameterType="com.sjh.entity.User">
insert into t_user(username, password, age) values (#{username}, #{password}, #{age})
</insert>
</mapper>
-
namespace
通常設置爲文件所在包+文件名的形式。 -
insert
標籤表示執行添加操作,select
標籤表示查詢操作,update
標籤表示更新操作,delete
標籤表示刪除操作。 -
id
屬性是實際調用 Mybatis 方法時需要用到的參數。 -
parameterType
屬性是調用對應方法時參數的數據類型。
在全局配置文件 config.xml
中配置UserMapper.xml
:
<mappers>
<mapper resource="com/sjh/mapper/UserMapper.xml"/>
</mappers>
調用 Mybatis 的原生接口執行添加操作:
public class MybatisTest {
public static void main(String[] args) {
//加載配置文件
InputStream is = MybatisTest.class.getClassLoader().getResourceAsStream("config.xml");
//創建 SqlSession 對象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sessionFactory.openSession();
//執行添加操作
String statement = "com.sjh.mapper.UserMapper.save";//拼接配置文件的 namespace + sql標籤的id
sqlSession.insert(statement, new User(1,"sjh","123",24));
sqlSession.commit();
sqlSession.close();
}
}
執行之後查看數據庫:
Mapper 代理實現自定義接口
自定義接口和方法:
public interface UserRepo {
int save(User user);
int update(User user);
int deleteById(Integer id);
List<User> findAll();
User findById(Integer id);
}
編寫與方法相對應的 UserRepo.xml
文件:
statement 標籤可根據 SQL 執行的業務選擇 insert、delete、update、select標籤中的一個。
Mybatis 框架會根據規則自動創建接口的實現類的代理對象。
規則:
- XML 文件中 namespace 的值爲接口的全類名。
- XML 文件中 statement 的
id
爲接口中對應的方法名。 - XML 文件中 statement 的
parameterType
和接口中對應方法的參數類型一致。 - XML 文件中 statement 的
resultType
和接口中對應方法的返回值類型一致。
<?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.sjh.repository.UserRepo">
<insert id="save" parameterType="com.sjh.entity.User">
insert into t_user(username, password, age) values (#{username}, #{password}, #{age})
</insert>
<update id="update" parameterType="com.sjh.entity.User">
update t_user set username = #{username}, password = #{password}, age = #{age})
</update>
<delete id="deleteById" parameterType="java.lang.Integer">
delete from t_user where id = #{id}
</delete>
<select id="findAll" resultType="com.sjh.entity.User">
select * from t_user
</select>
<select id="findById" parameterType="java.lang.Integer" resultType="com.sjh.entity.User">
select * from t_user where id = #{id}
</select>
</mapper>
在全局配置文件 config.xml
中配置UserRepo.xml
:
<mapper resource="com/sjh/repository/UserRepo.xml"/>
通過接口的代理對象執行查詢操作:
public static void main(String[] args) {
//加載配置文件
InputStream is = MybatisTest.class.getClassLoader().getResourceAsStream("config.xml");
//創建 SqlSession 對象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sessionFactory.openSession();
//獲取實現接口的代理對象
UserRepo userRepo = sqlSession.getMapper(UserRepo.class);
List<User> users = userRepo.findAll();
for(User user : users)
System.out.println(user);
sqlSession.close();
}
查詢結果:
Mapper 配置文件
statement 標籤
select、insert、update、delete 分別對應查詢、添加、更新、刪除操作
parameterType
:參數數據類型
-
基本數據類型
<select id="findById" parameterType="int" resultType="com.sjh.entity.User"> select * from t_user where id = #{id} </select>
-
String 類型
<select id="findByName" parameterType="java.lang.String" resultType="com.sjh.entity.User"> select * from t_user where username = #{username} </select>
-
包裝類型
<select id="findById" parameterType="java.lang.Integer" resultType="com.sjh.entity.User"> select * from t_user where id = #{id} </select>
-
多個參數,使用 arg0 表示第一個參數,arg1 表示第二個參數。
<select id="findByNameAndAge" resultType="com.sjh.entity.User"> select * from t_user where username = #{arg0} and age = ${arg1} </select>
-
Java Bean 類型
<update id="update" parameterType="com.sjh.entity.User"> update t_user set username = #{username}, password = #{password}, age = #{age}) </update>
resultType
:結果類型
-
基本數據類型
<select id="count" resultType="int"> select count(*) from t_user </select>
-
包裝類
<select id="count" resultType="java.lang.Integer"> select count(*) from t_user </select>
-
String 類型
<select id="findNameById" parameterType="java.lang.Integer" resultType="java.lang.String"> select username from t_user where id = #{id} </select>
-
Java Bean 類型
<select id="findById" parameterType="java.lang.Integer" resultType="com.sjh.entity.User"> select * from t_user where id = #{id} </select>
級聯查詢
一對多
以班級-學生爲例,首先創建數據庫表:
CREATE TABLE t_classes (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
)
CREATE TABLE t_student (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
cid INT,
CONSTRAINT fk FOREIGN KEY(cid) REFERENCES t_classes(id)
)
創建對應的實體類:
@Data
public class Classes {
private Integer id;
private String name;
private List<Student> students;
}
-----
@Data
public class Student {
private Integer id;
private String name;
private Classes classes;
}
創建接口 StudentRepo
及對應的 StudentRepo.xml
:
public interface StudentRepo {
//通過id查詢學生的信息
Student findById(Integer id);
}
<?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.sjh.repository.ClassesRepo">
<resultMap id="studentMap" type="com.sjh.entity.Student">
<id property="id" column="id"/>
<result property="name" column="name" />
<association property="classes" javaType="com.sjh.entity.Classes">
<id property="id" column="cid"/>
<result property="name" column="cname"/>
</association>
</resultMap>
<select id="findById" parameterType="java.lang.Integer" resultMap="studentMap">
SELECT s.id,s.name,c.id AS cid,c.name AS cname
FROM t_student AS s, t_classes AS c
WHERE s.cid = c.id AND s.id = #{id};
</select>
</mapper>
在全局配置文件 config.xml
中配置StudentRepo.xml
:
<mapper resource="com/sjh/repository/StudentRepo.xml"/>
測試代碼:
public static void main(String[] args) {
//加載配置文件
InputStream is = MybatisTest.class.getClassLoader().getResourceAsStream("config.xml");
//創建 SqlSession 對象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sessionFactory.openSession();
//獲取實現接口的代理對象
StudentRepo studentRepo = sqlSession.getMapper(StudentRepo.class);
System.out.println(studentRepo.findById(1));
sqlSession.close();
}
運行結果:
多對一
創建接口 ClassesRepo
及對應的 ClassesRepo.xml
:
public interface ClassesRepo {
//通過id查詢班級的信息
Classes findById(Integer id);
}
<?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.sjh.repository.ClassesRepo">
<resultMap id="classesMap" type="com.sjh.entity.Classes">
<id property="id" column="cid"/>
<result property="name" column="cname" />
<collection property="students" ofType="com.sjh.entity.Student">
<id property="id" column="id"/>
<result property="name" column="name"/>
</collection>
</resultMap>
<select id="findById" parameterType="java.lang.Integer" resultMap="classesMap">
SELECT s.id,s.name,c.id AS cid,c.name AS cname
FROM t_student AS s, t_classes AS c
WHERE s.cid = c.id AND c.id = #{id};
</select>
</mapper>
在全局配置文件 config.xml
中配置ClassesRepo.xml
:
<mapper resource="com/sjh/repository/ClassesRepo.xml"/>
測試代碼:
public static void main(String[] args) {
//加載配置文件
InputStream is = MybatisTest.class.getClassLoader().getResourceAsStream("config.xml");
//創建 SqlSession 對象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sessionFactory.openSession();
//獲取實現接口的代理對象
ClassesRepo classesRepo = sqlSession.getMapper(ClassesRepo.class);
System.out.println(classesRepo.findById(1));
sqlSession.close();
}
運行結果:
多對多
以客戶和商品的關係爲例,首先創建數據庫表:
CREATE TABLE customer (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
)
CREATE TABLE goods (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
)
CREATE TABLE customer_goods (
id INT PRIMARY KEY AUTO_INCREMENT,
cid INT,
gid INT,
CONSTRAINT fk1 FOREIGN KEY(cid) REFERENCES customer(id),
CONSTRAINT fk2 FOREIGN KEY(gid) REFERENCES goods(id)
)
創建對應的實體類:
@Data
public class Customer {
private Integer id;
private String name;
private List<Goods> goods;
}
---
@Data
public class Goods {
private Integer id;
private String name;
private List<Customer> customers;
}
創建接口 CustomerRepo
及對應的 CustomerRepo.xml
配置文件:
public interface CustomerRepo {
Customer findById(Integer id);
}
<?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.sjh.repository.CustomerRepo">
<resultMap id="customerMap" type="com.sjh.entity.Customer">
<id property="id" column="cid"/>
<result property="name" column="cname" />
<collection property="goods" ofType="com.sjh.entity.Goods">
<id property="id" column="gid"/>
<result property="name" column="gname"/>
</collection>
</resultMap>
<select id="findById" parameterType="java.lang.Integer" resultMap="customerMap">
SELECT c.id AS cid,c.name AS cname,g.id AS gid,g.name AS gname
FROM customer AS c,goods AS g,customer_goods cg
WHERE c.id = #{id} AND c.id = cg.cid AND g.id = cg.gid
</select>
</mapper>
在全局配置文件 config.xml
中配置CustomerRepoRepo.xml
:
<mapper resource="com/sjh/repository/CustomerRepo.xml"/>
測試代碼:
public static void main(String[] args) {
//加載配置文件
InputStream is = MybatisTest.class.getClassLoader().getResourceAsStream("config.xml");
//創建 SqlSession 對象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sessionFactory.openSession();
//獲取實現接口的代理對象
CustomerRepo customerRepo = sqlSession.getMapper(CustomerRepo.class);
System.out.println(customerRepo.findById(1));
sqlSession.close();
}
運行結果:
逆向工程
Mybatis 框架需要:實體類、自定義 Mapper 接口、對應的 Mapper.xml
傳統開發中上述三個組件需要開發者手動創建,逆向工程可以幫助開發者自動創建三個組件,減輕開發者的工作量。
Mybatis Generator,簡稱 MBG,是一個專門爲 Mybatis 框架開發者定製的代碼生成器,可自動生成所需的實體類,Mapper 接口和對應的 xml 文件,支持基本的 CRUD 操作。
在 pom.xml
引入依賴:
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
創建 MBG 配置文件 generator.xml
:
-
jdbcConnection
配置數據庫連接信息 -
javaModelGenerator
配置Java Bean 生成策略 -
sqlMapGenerator
配置 SQL 映射文件生成策略 -
javaClientGenerator
配置 Mapper 接口的生成策略 -
table
配置目標數據表
<?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>
<context id="test" targetRuntime="MyBatis3">
<jdbcConnection
driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql:///mybatis?useUnicode=true&serverTimezone=UTC"
userId="root"
password="sjh2019"
/>
<javaModelGenerator targetPackage="com.sjh.entity" targetProject="./src/main/java"/>
<sqlMapGenerator targetPackage="com.sjh.repository" targetProject="./src/main/java"/>
<javaClientGenerator type="XMLMAPPER" targetPackage="com.sjh.repository" targetProject="./src/main/java"/>
<table tableName="t_user" domainObjectName="User"/>
</context>
</generatorConfiguration>
創建執行類:
public class GeneratorTest {
public static void main(String[] args) {
List<String> warnings = new ArrayList<>();
boolean overwrite = true;
String generatorCig = "/generatorConfig.xml";
File file = new File(GeneratorTest.class.getResource(generatorCig).getFile());
ConfigurationParser configurationParser = new ConfigurationParser(warnings);
Configuration configuration = null;
try {
configuration = configurationParser.parseConfiguration(file);
} catch (IOException | XMLParserException e) {
e.printStackTrace();
}
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = null;
try {
assert configuration != null;
myBatisGenerator = new MyBatisGenerator(configuration, callback, warnings);
} catch (InvalidConfigurationException e) {
e.printStackTrace();
}
try {
assert myBatisGenerator != null;
myBatisGenerator.generate(null);
} catch (SQLException | InterruptedException | IOException e) {
e.printStackTrace();
}
}
}
延遲加載
延遲加載也叫懶加載,使用延遲加載可以提高程序的運行效率,針對於數據持久層,在某些特定情況下訪問特定數據庫,在其他情況下可以不訪問某些表,從一定程度上減少了 Java 應用與數據庫的交互次數。
查詢班級-學生時,學生和班級是兩張不同的表,如果當前需求只需要獲取學生信息,那麼查詢學生單表即可,如果需要通過學生獲取班級的信息則必須查詢兩張表。
不同業務需求需要查詢不同的表,根據具體的業務需求來動態減少數據表查詢的工作就是延遲加載。
在 StudentRepo 接口增加方法:
//通過id查詢學生的信息
Student findByIdLazy(Integer id);
對應的 XML 增加配置:
<resultMap id="studentMapLazy" type="com.sjh.entity.Student">
<id property="id" column="id"/>
<result property="name" column="name" />
<association property="classes" javaType="com.sjh.entity.Classes"
select="com.sjh.repository.ClassesRepo.findByIdLazy" column="cid"/>
</resultMap>
<select id="findByIdLazy" parameterType="java.lang.Integer" resultMap="studentMapLazy">
SELECT * FROM t_student WHERE id = #{id};
</select>
在 ClassesRepo 接口增加方法:
//通過id查詢班級的信息
Classes findByIdLazy(Integer id);
對應的 XML 增加配置:
<select id="findByIdLazy" parameterType="java.lang.Integer" resultType="com.sjh.entity.Classes">
SELECT * FROM t_classes WHERE id = #{id};
</select>
在 config.xml
增加配置:
<settings>
<!-- 打印 SQL -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!-- 開啓延遲加載 -->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
當輸出一個學生對象時,進行了2次查詢:
StudentRepo studentRepo = sqlSession.getMapper(StudentRepo.class);
System.out.println(studentRepo.findByIdLazy(1));
當只輸出學生對象的姓名時,不會查詢班級信息:
StudentRepo studentRepo = sqlSession.getMapper(StudentRepo.class);
System.out.println(studentRepo.findByIdLazy(1).getName());
Mybatis 緩存
使用緩存可以減少 Java 程序和數據庫交互的次數,從而提高程序的運行效率。例如查詢出 id = 1 的對象,第一次查詢之後會自動將該對象保存到緩存中,下一次查詢時直接從緩存中返回結果無需再次查詢數據庫。
Mybatis 緩存分類:
-
一級緩存
SqlSession 級別,默認開啓且不能關閉。
操作數據庫時需要創建 SqlSession 對象,在對象中有一個 HashMap 用於存儲緩存數據,不同 SqlSession 之間緩存數據區域互不影響。
一級緩存的作用域是 SqlSession 範圍的,在同一個 SqlSession 中執行兩次相同的 SQL 語句時,第一次執行完畢會將結果保存在緩存中,第二次查詢直接從緩存中獲取。
如果 SqlSession 執行了 DML 操作(insert、update、delete),Mybatis 必須將緩存清空以保證數據的有效性。
-
二級緩存
Mapper 級別,默認關閉。
使用二級緩存時多個 SqlSession 使用同一個 Mapper 的 SQL 語句操作數據庫,得到的數據會存在二級緩存區,同樣使用 HashMap 進行數據存儲,相比於一級緩存,二級緩存範圍更大,多個 SqlSession 可以共用二級緩存,作用域是 Mapper 的同一個 namespace,不同 SqlSession 兩次執行相同的 namespace 下的 SQL 語句,參數也相等,則第一次執行成功後會將數據保存在二級緩存中,第二次可直接從二級緩存中取出數據。
一級緩存
同一個 SqlSession 執行兩次查詢,只會查詢一次數據庫:
public static void main(String[] args) {
//加載配置文件
InputStream is = MybatisTest.class.getClassLoader().getResourceAsStream("config.xml");
//創建 SqlSession 對象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sessionFactory.openSession();
//獲取實現接口的代理對象
StudentRepo studentRepo = sqlSession.getMapper(StudentRepo.class);
System.out.println(studentRepo.findByIdLazy(1).getName());
System.out.println(studentRepo.findByIdLazy(1).getName());
sqlSession.close();
}
二級緩存
Mybatis 自帶的二級緩存,在 config.xml
中配置:
<!-- 開啓二級緩存 -->
<setting name="cacheEnabled" value="true"/>
在對應的 Mapper.xml 中配置一個 cache 標籤即可:
<cache/>
對應實體類實現序列化接口:
public class Student implements Serializable
不同 SqlSession 執行兩次查詢,只會查詢一次數據庫:
public static void main(String[] args) {
//加載配置文件
InputStream is = MybatisTest.class.getClassLoader().getResourceAsStream("config.xml");
//創建 SqlSession 對象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sessionFactory.openSession();
//獲取實現接口的代理對象
StudentRepo studentRepo = sqlSession.getMapper(StudentRepo.class);
System.out.println(studentRepo.findByIdLazy(1).getName());
//關閉sqlSession,測試二級緩存
sqlSession.close();
sqlSession = sessionFactory.openSession();
studentRepo = sqlSession.getMapper(StudentRepo.class);
System.out.println(studentRepo.findByIdLazy(1).getName());
sqlSession.close();
}
)
使用第三方二級緩存,在 pom.xml
添加依賴:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.4.3</version>
</dependency>
添加 ehcache.xml
:
<ehcache>
<diskStore/>
<defaultCache
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
在 config.xml
中配置:
<!-- 開啓二級緩存 -->
<setting name="cacheEnabled" value="true"/>
在對應的 Mapper.xml 中配置:
<cache type="org.mybatis.caches.ehcache.EhcacheCache">
<!-- 緩存創建後,最後一次訪問緩存的時間至緩存失效的時間間隔 -->
<property name="timeToIdleSeconds" value="3600"/>
<!-- 緩存創建後自失效的時間間隔 -->
<property name="timeToLiveSeconds" value="3600"/>
<!-- 緩存回收策略 -->
<property name="memoryStoreEvictionPolicy" value="LRU"/>
</cache>
Mybatis 動態 SQL
作用:簡化代碼開發,程序可以自動根據業務參數決定 SQL 語句的組成。
if 標籤
如果 test 中表達式的結果不成立則不添加該語句到 SQL 語句。
<select id="findByUser" parameterType="com.sjh.entity.User" resultType="com.sjh.entity.User">
select * from t_user where
<if test="id != 0">
id = #{id}
</if>
<if test="username != null">
and username = #{username}
</if>
<if test="username != null">
and password = #{password}
</if>
<if test="age != 0">
and age = #{age}
</if>
</select>
where 標籤
where 可以自動判斷是否需要刪除 SQL 中的 and 關鍵字,通常與 if 結合使用。
<select id="findByUser" parameterType="com.sjh.entity.User" resultType="com.sjh.entity.User">
select * from t_user
<where>
<if test="id != 0">
id = #{id}
</if>
<if test="username != null">
and username = #{username}
</if>
<if test="username != null">
and password = #{password}
</if>
<if test="age != 0">
and age = #{age}
</if>
</where>
</select>
choose、when 標籤
類似 if
<select id="findByUser" parameterType="com.sjh.entity.User" resultType="com.sjh.entity.User">
select * from t_user
<where>
<choose>
<when test="id != 0">
id = #{id}
</when>
</choose>
<choose>
<when test="username != null">
and username = #{username}
</when>
</choose>
<choose>
<when test="password != null">
and password = #{password}
</when>
</choose>
<choose>
<when test="age != 0">
and age = #{age}
</when>
</choose>
</where>
</select>
trim 標籤
prefix 和 suffix 屬性被用於生成實際的 SQL 語句,和標籤內部的語句進行拼接,如果語句前後出現了 prefixOverrides 或 suffixOverrides 屬性指定的值,Mybatis 會自動將其刪除。
<select id="findByUser" parameterType="com.sjh.entity.User" resultType="com.sjh.entity.User">
select * from t_user
<trim prefix="where" prefixOverrides="and">
<if test="id != 0">
id = #{id}
</if>
<if test="username != null">
and username = #{username}
</if>
<if test="username != null">
and password = #{password}
</if>
<if test="age != 0">
and age = #{age}
</if>
</trim>
</select>
set 標籤
用於 update 操作,會自動根據參數選擇生成 SQL 語句。
<update id="updateByPrimaryKeySelective" parameterType="com.sjh.entity.User">
update t_user
<set>
<if test="username != null">
username = #{username,jdbcType=VARCHAR},
</if>
<if test="password != null">
password = #{password,jdbcType=VARCHAR},
</if>
<if test="age != null">
age = #{age,jdbcType=INTEGER},
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>
foreach 標籤
可以迭代生成一系列值,主要用於 SQL 的 in 語句。
例如通過 id 集合查詢 User,先在實體類加入屬性:
private List<Integer> ids;
在接口中添加方法:
List<User> findByIds(User user);
在對應的 Mapper.xml 配置:
<select id="findByIds" parameterType="com.sjh.entity.User" resultType="com.sjh.entity.User">
select * from t_user
<where>
<foreach collection="ids" open="id in (" close=")" item="id" separator=",">
#{id}
</foreach>
</where>
</select>
測試方法:
public static void main(String[] args) {
//加載配置文件
InputStream is = MybatisTest.class.getClassLoader().getResourceAsStream("config.xml");
//創建 SqlSession 對象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession = sessionFactory.openSession();
//獲取Mapper代理對象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
user.setIds(ids);
System.out.println(userMapper.findByIds(user));
}
結果: