mybatis框架
概述
mybatis是基於java的持久層框架,內部封裝了jdbc,使開發者只關注sql語句本身。
mybatis通過xml和註解的方式將各種statement配置起來,並通過Java對象和statement中的動態參數進行映射最終生成sql語句,並對結果映射爲java對象並返回
mybatis採用ORM的思想方便操作等
ORM:
Object Relational Mapping 對應關係映射
簡單的來說就是:
將數據庫中的表和實體類及實體類的屬性對應起來
讓我們看可以操作實體類就可以實現操作數據庫表
表 實體類
user User
id user_id
name user_name
. .
. .
. .
mybatis 入門(xml實現)
創建一個maven項目,直接創建
在pom.xml加入依賴
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
在resource文件夾中創建mybatis的 --主配置-- 文件命名爲mysqlMapConfig.xml,
在主配置文件中配置我們的所有javabean對象的一些CRUD操作。
主配置文件主要功能:
1.配置連接的數據庫
2.配置文件映射,如:對UserDao的一些操作的文件映射,需要使用Mapper標籤
<?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">
<!-- mybatis 的 主配置文件-->
<configuration>
<!-- 配置環境-->
<environments default="mysql">
<!--配置mysql-->
<environment id="mysql">
<!--配置事務類型-->
<transactionManager type="JDBC"/>
<!--配置數據源/連接池-->
<dataSource type="POOLED">
<!--配置連接數據庫的基本信息-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://xx.xxx.xxx.xxx:3306/xxx"/>
<property name="username" value="xxxx"/>
<property name="password" value="xxx"/>
</dataSource>
</environment>
</environments>
<!--指定映射配置文件的位置,映射配置文件指的是每個dao獨立的配置文件-->
<mappers>
<mapper resource="club/twzw/dao/UserDao.xml"/>
</mappers>
</configuration>
在resources 文件夾下 創建UserDao.xml(與類名相一致,路徑也要一致,映射的配置文件相一致)
主要包括一些CRUD的操作,延遲加載等等。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org.//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="club.twzw.dao.UserDao"> <<<<<------這裏的namespace 必須和 接口進行綁定,也就是接口的全類名路徑,且各個標籤使用的id爲接口中定義的名稱,接口名爲findAll,標籤使用的id也爲findAll,完成綁定。
<select id="findAll" resultType="club.twzw.domain.User">
select * from user
</select>
</mapper>
在resources 文件夾下 創建log4j.properties文件,用於輸入日誌文件
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
創建dao處理層接口,用於一些CRUD操作的方法,
package club.twzw.dao;
import club.twzw.domain.User;
import java.util.List;
/**
* 用戶持久層接口
*/
public interface UserDao {
/**
* 查詢所有操作
*/
List<User> findAll();
}
創建bean對象,用於存儲數據
package club.twzw.domain;
import java.io.Serializable;
public class User implements Serializable {
private Integer id;
private String name;
private String born;
private Integer sex;
private String address;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", born='" + born + '\'' +
", sex=" + sex +
", address='" + address + '\'' +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBorn() {
return born;
}
public void setBorn(String born) {
this.born = born;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
創建測試函數,factory.openSession();爲空需要手動提交,factory.openSession(true);爲自動提交
package club.twzw.test;
import club.twzw.dao.UserDao;
import club.twzw.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class mybatisTest {
public static void main(String[] args) throws IOException {
// 讀取配置文件,爲主配置文件
InputStream in = Resources.getResourceAsStream("mysqlMapConfig.xml");
// 創建SqlSessionFactory 工廠
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//使用工廠生產session
SqlSession sqlSession = factory.openSession();
// 使用sqlsession創建dao接口的代理對象,傳入接口
UserDao userDao = sqlSession.getMapper(UserDao.class);
// 使用代理對象執行方法
List<User> users = userDao.findAll();
for (User user:users){
System.out.println(user);
}
//釋放資源
in.close();
sqlSession.close();
}
}
最終實現效果控制檯輸出
User{id=1, name='comi', born='1998', sex=0, address='xxxx'}
User{id=2, name='siki', born='2002', sex=1, address=' xxxx'}
mybatis 注意事項
一、創建UserDao.xml和UserDao.java時名稱是爲了和我們之前的知識保持一致
在mybatis中它把持久層的操作接口名稱和映射文件也叫做 Mapper
所以 UserDao 和 UserMapper 是一樣的
二、mybatis的映射配置文件位置必須與dao接口的包結構相同
三、映射配置文件的mapper標籤namespace屬性的取值必須是dao接口的全限定類名
四、映射配置文件的操作配置(select),id屬性的取值必須是dao接口的方法名
當我們遵循二、三、四點後,在開發中便~~~無須實現dao實現類~~~
Sqlsession和connection都是非線程安全的,不能放在成員變量中,每一次使用都應該去獲取新的對象
mybatis 引用外部文件配置數據庫連接
新建一個dbconfig.properties文件,在主配置文件下 添加以下語句,並且修改配置文件的properties
<properties resource="dbconfig.properties"/>
<environments default="mysql">
<!--配置mysql-->
<environment id="mysql">
<!--配置事務類型-->
<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>
dbconfig.properties文件內容
jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://xx.xx.xx.xx:3306/blog
jdbc.username = blog
jdbc.password = 146325
主配置文件的常用標籤
setting
在這裏,可以配置相關的全局設置,比如懶加載,駝峯命名等等設置。
typeAliases 別名處理器
可以爲我們常用的Java類起別名,讓很長的名字變得短,別名不區分大小寫。在主配置文件下就爲全局配置,在單獨的UserDao中就爲局部別名。
package可以批量起別名,自動爲package下的類自動起別名
<settings>
<!--懶加載-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiceLazyLoading" value="false"/>
<!--開啓駝峯命名自動轉換-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--如果不配置alias就會默認爲類名的小寫-->
<typeAliases>
<typeAlias type="club.twzw.dao.UserDao" alias="user"/>
</typeAliases>
<!-包下所有類自動起別名-->
<package name="club.twzw.dao"/>
mappers 將sql映射註冊到全局配置中 mapper 註冊一個sql映射
resource:引用類路徑下的sql映射文件
url:引入網絡路徑或者磁盤路徑下的sql映射文件
class:引入(註冊)接口
1.有sql文件,sql文件必須和接口同名且在同一目錄
2.註解實現
推薦比較重要的Dao接口可以用xml實現,不太重要的可以使用註解實現,提高開發速度
批量註冊
使用package標籤,註冊該包下所有的映射,如果是xml文件,同樣,sql文件必須和接口同名且在同一目錄,才能實現註冊
<package name="club.twxw.dao.UserDao"/>
databaseIdProvider 使用不同的數據庫
且每一個標籤都有各自的使用順序,否者會報錯。
<databaseIdProvider type="DB_VEBDOR">
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
</databaseIdProvider>
mybatis(註解實現映射)
1.無需在配置UserDao.xml文件
2.將mysqlMapConfig.xml的mapper屬性的resource改爲class,並配置全路徑類名
<mappers>
<mapper class="club.twzw.dao.UserDao"/>
</mappers>
3.將UserDao的findAll方法上加入註解@Select()
@Select("select * from user")
List<User> findAll();
增加代碼的複用性
由於每一次使用dao都會有一些重複的過程,我們可以把這些重複的額過程提取出來,不但方便使用,而且代碼簡潔。
比如說:我們可以在代碼運行之前,銷燬之前運行一些代碼
@Before
public void init() throws IOException {
// 讀取配置文件
in = Resources.getResourceAsStream("mysqlMapConfig.xml");
// 創建SqlSessionFactory 工廠
builder = new SqlSessionFactoryBuilder();
factory = builder.build(in);
//使用工廠生產session
sqlSession = factory.openSession();
// 使用sqlsession創建dao接口的代理對象
userDao = sqlSession.getMapper(UserDao.class);
}
@After
public void destory() throws Exception{
sqlSession.commit();
//釋放資源
in.close();
sqlSession.close();
}
這樣我們就可以簡化代碼,徹底專注於核心業務dao層
@Test
public void testSave() throws IOException {
User user = new User();
user.setAddress("japan");
user.setBorn("1998");
user.setName("gimi");
user.setSex(1);
user.setId(3);
// 使用代理對象執行方法
userDao.addUser(user); <<<-----
//sqlSession.commit(); <<<-----必須要提交事務,否則無法實現CRUD操作,同樣,也可以把這一句放在銷燬之前,但是這一句便不能再出現
}
當然,還需要再UserDao.xml 中 加入相應的id addUser
<insert id="addUser" parameterType="club.twzw.domain.User">
insert into user (id,name,born,sex,address)values(#{id},#{name},#{born},#{sex},#{address})
</insert>
完善CRUD相關代碼及模糊查詢
//findById
@Test
public void testDelete(){
User user = userDao.findById(1);
System.out.println(user);
}
//add
@Test
public void testSave() throws IOException {
User user = new User();
user.setAddress("japan");
user.setBorn("1998");
user.setName("gimi");
user.setSex(1);
user.setId(3);
// 使用代理對象執行方法
userDao.addUser(user);
}
//update
@Test
public void testUpdate(){
User user = new User();
user.setId(3);
user.setSex(1);
user.setName("???");
user.setAddress("djkajdjwa");
user.setBorn("20000000000");
userDao.UpdateUser(user);
}
//delete
@Test
public void testDelete(){
userDao.delete(3);
}
// 模糊查詢
@Test
public void findByName() {
List<User> users = userDao.findByName("%comii%");
for (User user : users) {
System.out.println(user);
}
}
配置相關xml,namespace 需和類路徑相同,與接口進行綁定,且#{xxx}中的名稱爲JavaBean中的屬性名稱相同,User中有name,sex,address,那麼xml文件中的#{xxx} 也爲#{name},#{sex},#{address}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org.//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="club.twzw.dao.UserDao">
<!-- // 有時數據庫和java bean 中的命名不一致,爲了方便起見,我們可以配置resultMap(結果集)-->
<!-- // 配置查詢結果的列名和實體類的屬性名對應的關係(如果命名不一致,一致無需創建)-->
<resultMap id="userMap" type="club.twzw.domain.User">
<!-- 主鍵對應字段-->
<id property="id" column="id"></id>
<!-- 非主鍵對應字段-->
<result property="name" column="name"></result>
<result property="born" column="born"></result>
<result property="sex" column="sex"></result>
</resultMap>
<!--使用resultMap-->
<!--查詢所有-->
<select id="findAll" resultMap="userMap">
select * from user
</select>
<!--不使用resultMap-->
<!--查詢所有-->
<select id="findAll" resultType="club.twzw.domain.User">
select * from user
</select>
<!--查詢單個-->
<select id="findById" parameterType="int" resultType="club.twzw.domain.User">
select * from user where id = #{id}
</select>
<!--添加用戶-->
<insert id="addUser" parameterType="club.twzw.domain.User">
insert into user (id,name,born,sex,address)values(#{id},#{name},#{born},#{sex},#{address})
</insert>
<!--更新用戶數據-->
<update id="UpdateUser" parameterType="club.twzw.domain.User">
update user set name=#{name},address=#{address},sex=#{sex},born=#{born} where id=#{id}
</update>
<!--刪除用戶數據-->
<delete id="delete" parameterType="Integer">
delete from user where id=#{id}
</delete>
<!--根據name模糊查詢用戶-->
<select id="findByName" parameterType="string" resultType="club.twzw.domain.User">
select * from user where name like #{name}
</select>
</mapper>
在插入完成之後獲取ID的值
1.通過selectKey標籤 設置resultType,keyProperty,keyColumn,order 相關設置,自動返回數據。(不支持自增的數據庫使用的方法,Oracle),order=“BEFORE” 在執行插入之前
2.使用useGeneratedKeys=“true” keyProperty=“id”,這裏的id 爲JavaBean的id(支持自增的數據庫,mysql)
<!--方法一-->
<insert id="addUser" parameterType="club.twzw.domain.User">
<selectKey resultType="int" keyProperty="int" keyColumn="id" order="BEFORE">
<!--查詢主鍵id,得到後便可以使id有值-->
select last_intsert_id();
</selectKey>
insert into user (id,name,born,sex,address)values(#{id},#{name},#{born},#{sex},#{address})
</insert>
<!--方法二-->
<insert id="addUser" parameterType="user" useGeneratedKeys="true" keyProperty="id">
insert into user (name,born,sex,address)values(#{name},#{born},#{sex},#{address})
</insert>
OGNL表達式(object graphic navigation language)
通過對象的取值方法 來獲取數據,在寫法上省略了get(省略相關配置)
eg:
類: User.GetName();
ONNL: User.name
使用alias 配置別名
<!-- 使用alias配置別名-->
<!-- <typeAliases>-->
<!-- <typeAlias type="club.twzw.domain.User" alias="user"></typeAlias>-->
<!-- </typeAliases>-->
<!-- 那麼所有的club.twzw.domain.User 便可以用 user 替代-->
<!-- <select id="findById" parameterType="int" resultType="user">-->
<!-- select * from user where id = #{id}-->
<!-- </select>-->
mtbatics 中的動態sql語句查詢 -if
UserDao.xml 中添加
<!-- 根據條件查詢-->
<select id="findByCondition" resultType="club.twzw.domain.User" parameterType="club.twzw.domain.User">
select * from user where 1 = 1 <<<<<----------
<if test="name != null">
and name = #{name}
</if>
</select>
UserDao.java 中添加
boolean findByCondition(User user);
測試代碼
@Test
public void findByCondition() {
User u = new User();
u.setName("comi");
User u = userDao.findByCondition(u);
System.out.println(u);
}
mtbatics 中的動態sql語句查詢 -where
<!--使用where 標籤-->
<select id="findByCondition" resultType="club.twzw.domain.User" parameterType="club.twzw.domain.User">
select * from user <<<<<----------
<where> <<<<<----------
<if test="name != null">
and name = #{name}
</if>
<if test="sex != null">
and sex = #{sex}
</if>
</where>
</select>
將重複使用的 sql 語句,抽取出來,重複使用
<!--由於我們經常使用 select * from user 這條語句,所以我們可以把這條語句抽取出來-->
<sql id="selectUserAll"> <<<<<----------
select * from user;
</sql>
<!-- 使用 sql-->
<select id="findAll" resultType="club.twzw.damain.User">
<include refid="selectUserAll"></include> <<<<<----------
</select>
mtbatics 中的動態sql語句–批量查詢,-foreach
sql 語句 select * from user where id in (41,42,43);
mybatis 實現
<!-- 查詢多個指定id的數據-->
<select id="findByUsersIds" resultType="club.twzw.damain.User" parameterType="club.twzw.damain.User">
select * from user
<where>
<if test="ids != null and ids.size()>0">
<foreach collection="ids" open=" and ids in (" close=")" item="id" separator=",">
#{id}
</foreach>
</if>
</where>
</select>
mtbatics 中的動態sql語句–批量保存,-foreach
接口定義
void addUsers(@Param("users")List<User> users);
xml語句
<insert id="saveUsers" parameterType="domain.User">
insert INTO user(name,gender,email)values
<foreach collection="users" item="user" separator=",">
(#{user.name},#{user.gender},#{user.email})
</foreach>
</insert>
mtbatics 中字符截取,-trim
如果gender爲空,那麼會在結尾多出來一個and,而suffixOverrides就是用來截取and的功能
<select id="findByCondition" resultType="domain.User" parameterType="string">
select * from user
<trim suffixOverrides="and">
<where>
<if test="name !=''">
and name like #{name} and
</if>
<if test="gender !=''">
gender = #{gender}
</if>
</where>
</trim>
</select>
mtbatics 中字符截取,-choose,類似於switch case選擇分支語句
<select id="findByCondition" parameterType="string" resultType="domain.User">
select *
from user
<where>
<choose>
<when test="id != ''">
id=#{id}
</when>
<when test="gender != ''">
gender=#{gender}
</when>
<otherwise>
email=#{email}
</otherwise>
</choose>
</where>
</select>
mtbatics 中數據更新,-set
<update id="updateByCondition" parameterType="string">
update user
<set>
<if test="name !=''">
name=#{name},
</if>
<if test="gender !=''">
gender=#{gender}
</if>
</set>
where id=#{id}
</update>
單個參數和多個參數
如果是單個參數或者javaBe對象,mybatis會自動識別,無需特別處理,但是如果是多個參數,則需要特殊處理
使用@Param註解,在接口中使用
boolean addUser(@Param("id")Interger id,@Param("name")String name);
在xml中直接使用key即可
<select id="findByCondition" resultMap="userMap">
select * from user where id = #{id} and name =#{name}
</select>
將不相關的數據進行封裝成一個參數
java代碼中
Map<String,Object> map = new HashMap<>();
map.put("id",1);
map.put("name","comi");
User u = userDao.findByCondition(mao);
xml就可以直接使用#{id},#{name}
<select id="findByCondition" resultMap="userMap">
select * from user where id = #{id} and name =#{name}
</select>
select 標籤
1.使用select 封裝 List,如果返回數據爲多個,mybatis會自動封裝返回的數據爲list
2.使用select 封裝 Map,resultMap 設置爲Map(單個數據)
3.使用select 封裝 Map,在方法上添加 @MapKey(“id”) 指定 key,就可以自動封裝
@MapKey("id")
public Map<Interger,User> map getUserByCondition(String name);
resultMap 自定義結果集(如果數據庫和JavaBean數據名稱對應不一致)
<resultMap id="userMap" type="club.twzw.domain.User">
<!-- 主鍵對應字段-->
<id property="id" column="Id"></id>
<!-- 非主鍵對應字段-->
<result property="name" column="Name"></result>
<result property="born" column="Born"></result>
<result property="sex" column="Sex"></result>
</resultMap>
resultMap中返回的結果中一個類包含另一個類的情況(聯合查詢)
有兩個JavaBean對象,一個是User,一個是account,在查詢user時需要查詢account。
user
id
name
gender
acc
account
id
money
進行設置結果集
<!--方法一-->
<resultMap id="userMap" type="club.twzw.domain.User">
<!-- 主鍵對應字段-->
<id property="id" column="Id"></id>
<!-- 非主鍵對應字段-->
<result property="name" column="Name"></result>
<result property="born" column="Born"></result>
<result property="gender" column="Gender"></result>
<result property="aid" column="account.id"></result> <<<<---------
<result property="amonty" column="account.money"></result> <<<<---------
</resultMap>
<!--方法二-->
<!--property 指的是 要封裝的JavaBean中的屬性是哪一個-->
<!--javaType 這個屬性對象的類型,即account-->
<association property="acc" column="id" javaType="club.twzw.domain.account">
<result property="aid" column="id"></result> <<<<---------
<result property="amonty" column="money"></result> <<<<---------
</association>
mybatis 延遲加載和立即加載
什麼是延遲加載?
在真正使用數據時,才發起查詢,不用的時候不查詢,按需加載(懶加載)
什麼是立即加載?
不管用不用,只要一調用方法,馬上發起查詢。
在對應的四種表關係中:一對一,多對一(mytatis 沒有這個概念),一對多,多對多。不同情況使用不同的加載策略。
一對多,多對多:採用延遲加載
一對一,多對一:採用立即加載
配置延遲加載
全局配置文件中加入(如果不加入這兩句,就會變爲分步查詢)
<!--在這裏配置相關懶加載參數-->
<!--這樣 懶加載的配置就配置好了-->
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiceLazyLoading" value="false"/>
</settings>
mybatis 返回數據中子屬性爲單個JavaBean
在UserDao.xml 中配置 resultMap的association標籤屬性,重點是select 屬性,必須是namespace加方法名,唯一標識用戶,通過此方法去查出信息
<!--配置延遲加載-->
<resultMap id="userMap" type="club.twzw.domain.User">
<!--主鍵對應字段-->
<id property="id" column="id"></id>
<!--非主鍵對應字段-->
<result property="name" column="name"></result>
<result property="born" column="born"></result>
<result property="sex" column="sex"></result>
<!--使用association 標籤-->
<!--select 屬性指定的內容是查詢用戶的唯一標識-->
<!--同樣 column 也是必須的,否則無法運行,會報錯-->
<!--這樣我們就可以配置相關連的對象了,比如說用戶的賬戶信息等!-->
<association property="user" column="id" javaType="user" select="club.twzw.dao.UserDao.findById"> <<<<<---------
</association>
</resultMap>
mybatis 返回數據中子屬性爲集合
使用標籤collection
collection定義關聯集合的屬性的封裝規則
ofType指定集合中的元素類型
<resultMap id="userMap" type="club.twzw.domain.User">
<!--主鍵對應字段-->
<id property="id" column="id"></id>
<!--非主鍵對應字段-->
<result property="name" column="name"></result>
<result property="born" column="born"/>
<result property="sex" column="sex"></result>
<collection property="account" ofType="club.twzw.domain.account">
<!--主鍵對應字段-->
<id property="aid" column="id"></id>
<!--非主鍵對應字段-->
<result property="amoney" column="money"></result>
</collection>
</resultMap>
同樣,按需加載也是需要設定select屬性並書寫相應的xml查詢語句
resultMap 鑑別器 discriminator (類似於switch)
加入我們需要根據不同的部門來查詢封裝信息,則需要使用discriminator標籤
javaType:傳入值類型
column:哪一列需要作爲判斷
<resultMap id="userMap" type="club.twzw.domain.User">
<!--主鍵對應字段-->
<id property="id" column="id"></id>
<!--非主鍵對應字段-->
<result property="name" column="name"></result>
<result property="born" column="born"/>
<result property="sex" column="sex"></result>
<discriminator javaType="String" column="department">
<case value="研發部">
<!--相關操作-->
</case>
<case value="設計部">
<!--相關操作-->
</case>
</discriminator>
</resultMap>
mybatis 緩存機制
二級緩存(全局緩存)
一級緩存(本地緩存)
與數據庫同一次會話期間查詢到的數據會放在本地緩存中,以後有相同數據,直接從緩存中拿,沒必要查詢數據庫,
在同一次會話中,相同的sql語句只會查詢一次,查詢結果被緩存在sqlsseesion中,一級緩存是一直開啓的。
一級緩存失效情況
1.sqlsession不同
2.sqlsession相同,查詢條件不同(當一級緩存還沒有這條數據)
3.sqlsession相同,兩次查詢之間執行了增刪改操作(這次修改可能對之前數據有影響)
4.手動清除cache緩存
@Test
void testFirstLevel() throws IOException {
InputStream in = Resources.getResourceAsStream("mysqlConfig.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
SqlSession session = factory.openSession(true);
try {
UserDao dao = session.getMapper(UserDao.class);
Map<Integer, User> users = dao.getUser("comi");
System.out.println(users);
} finally {
session.close();
}
}
二級緩存
基於namespace級別的緩存,一個namespace對應一個二級緩存
工作機制:
1.一個會話,查詢一條數據,這個數據就會放在當前會話的一級緩存中。
2.如果會話關閉,一級緩存中的數據會保存到二級緩存中,新的會話查詢信息,就可以參照二級緩存
3.SQL session
userMapper==>user
accountMapper==>account
使用步驟
在全局配置文件中開啓全局二級緩存(默認開啓)
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
在單獨的xml文件中配置二級緩存
<!-- 開啓緩存,設置刷新緩存間隔 60 秒 刷新規則:先進先出 且只讀-->
<cache readOnly="true" flushInterval="60000" eviction="FIFO"></cache>
JavaBean實現序列化接口
測試代碼:不同的sqlsession請求同一個數據,開啓二級緩存之後,還是隻會請求一次
@Test
void testSecondCache() throws IOException {
InputStream in = Resources.getResourceAsStream("mysqlConfig.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
SqlSession session = factory.openSession(true);
SqlSession session1 = factory.openSession(true);
try {
UserDao dao = session.getMapper(UserDao.class);
UserDao mapper = session1.getMapper(UserDao.class);
Map<Integer, User> comi = dao.getUser("comi");
System.out.println(comi);
session.close();
Map<Integer, User> user = mapper.getUser("comi");
System.out.println(user);
} finally {
session1.close();
}
}