Mybatis 快速入門實戰筆記

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&amp;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&amp;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));
}

結果:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章