【每日演算法】長度最小的子陣列
mybatis學習筆記
使用流程:
1.新建資料庫表對應的bean
2.工程下新建 lib 資料夾用於存放需要匯入的jar包(buildPath—>add to buildPath)
3.再新建一個資料夾 conf 存放配置檔案
(寫好log4j相應的配置檔案 log4J.xml )
4.從 XML 中構建 SqlSessionFactory
a.建立一個全域性配置xml檔案(mybatis-config.xml),配置
<?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> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/mybatis" /> <property name="username" value="root" /> <property name="password" value="123456" /> </dataSource> </environment> </environments> <!-- 將我們寫好的sql對映檔案(EmployeeMapper.xml)一定要註冊到全域性配置檔案(mybatis-config.xml)中 --> <mappers> <mapper resource="EmployeeMapper.xml" /> </mappers> </configuration>
b.建立一個sql對映對應的xml檔案(EmployeeMapper.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.atguigu.mybatis.EmployeeMapper"> <!-- namespace:名稱空間 id:唯一標識 resultType:返回值型別 (返回的是我們想從資料庫中得到的被封裝的型別) #{id}:從傳遞過來的引數中取出id值 --> <select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee"> select id,last_name lastName,email,gender from tbl_employee where id = #{id} </select> </mapper>
c.根據xml檔案(sql對映對應的xml檔案)建立一個sqlSessionFactory物件
@Test public void test() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 2、獲取sqlSession例項,能直接執行已經對映的sql語句 // sql的唯一標識:statement: Unique identifier matching the statement to use. // 執行sql要用的引數:parameter: A parameter object to pass to the statement. try { Employee employee = openSession.selectOne( //這裡的sql唯一表示推薦寫全地址(namespace + id) ,這裡含義即為獲取上面xml中配置對應id的sql語句 "com.atguigu.mybatis.EmployeeMapper.getEmpById", 1); System.out.println(employee); } finally { openSession.close(); } }
總結:
* 1、根據xml配置檔案(全域性配置檔案)建立一個SqlSessionFactory物件 有資料來源一些執行環境資訊
* 2、sql對映檔案;配置了每一個sql,以及sql的封裝規則等。
* 3、將sql對映檔案註冊在全域性配置檔案中
* 4、寫程式碼:
* 1)、根據全域性配置檔案得到SqlSessionFactory;
* 2)、使用sqlSession工廠,獲取到sqlSession物件使用他來執行增刪改查
* 一個sqlSession就是代表和資料庫的一次會話,用完關閉
* 3)、使用sql的唯一標誌來告訴MyBatis執行哪個sql。sql都是儲存在sql對映檔案中的。
以上為舊版本MyBatis的操作,現在有一種更簡潔的方式:
介面式程式設計:
1.首先定義一個介面:
import com.atguigu.mybatis.bean.Employee;
public interface EmployeeMapper {
public Employee getEmpById(Integer id);
}
2.重新配置sql對映對應的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.atguigu.mybatis.dao.EmployeeMapper">
<!--
namespace:名稱空間;指定為介面的全類名,以便將介面抽象類與這個配置檔案動態繫結
id:唯一標識
resultType:返回值型別
#{id}:從傳遞過來的引數中取出id值
public Employee getEmpById(Integer id);
-->
<select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee">
select id,last_name lastName,email,gender from tbl_employee where id = #{id}
</select>
</mapper>
3.測試:
@Test
public void test01() throws IOException {
// 1、獲取sqlSessionFactory物件
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
// 2、獲取sqlSession物件
//SqlSession的例項不是執行緒安全的,因此不能被共享,每次使用都需重新建立
SqlSession openSession = sqlSessionFactory.openSession();
try {
// 3、獲取介面的實現類物件
//會為介面自動的建立一個代理物件,代理物件去執行增刪改查方法
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Employee employee = mapper.getEmpById(1);
System.out.println(mapper.getClass());
System.out.println(employee);
} finally {
openSession.close();
}
}
總結:
* 1、介面式程式設計
* 原生: Dao ====> DaoImpl
* mybatis: Mapper ====> xxMapper.xml
*
* 2、SqlSession代表和資料庫的一次會話;用完必須關閉;
* 3、SqlSession和connection一樣她都是非執行緒安全。每次使用都應該去獲取新的物件。
* 4、mapper介面沒有實現類,但是mybatis會為這個介面生成一個代理物件。
* (將介面和xml進行繫結)
* EmployeeMapper empMapper = sqlSession.getMapper(EmployeeMapper.class);
* 5、兩個重要的配置檔案:
* mybatis的全域性配置檔案:包含資料庫連線池資訊,事務管理器資訊等...系統執行環境資訊
* sql對映檔案:儲存了每一個sql語句的對映資訊:
* 將sql抽取出來。
MyBatis全域性配置檔案(mybatis-config.xml):
引入dtd約束(規定約束xml檔案的定義和程式):
有網的條件下:
直接點選以上網址,即可下載,然後點選即可實現對於相應標籤的提示;
無網的條件下:
對應情況如下(另一個dtd檔案同理):
首先找到磁碟中MyBatis jar包的位置,以壓縮檔案形式開啟,找到相應的兩個檔案:
將這兩個檔案解壓出來,放到某一 目錄下;
將上述xml檔案中給的地址複製下來 http://mybatis.org/dtd/mybatis-3-mapper.dtd
點選 windows—>preferences—>xml—>選擇add
即可看到有相應提示:
另一個同理;
properties 引入外部配置檔案:
<?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>
<!--
1、mybatis可以使用properties來引入外部properties配置檔案的內容;
resource:引入類路徑下的資源(和當前檔案在同一個資料夾下)
url:引入網路路徑或者磁碟路徑下的資源
-->
<properties resource="dbconfig.properties"></properties>
</configuration>
dbconfig.properties檔案:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=123456
settings設定:
<!--
2、settings包含很多重要的設定項
setting:用來設定每一個設定項
name:設定項名
value:設定項取值
-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
更多使用參考:
typeAliases:
<!-- 3、typeAliases:別名處理器:可以為我們的java型別起別名
別名不區分大小寫
-->
<typeAliases>
<!-- 1、typeAlias:為某個java型別起別名
type:指定要起別名的型別全類名;預設別名就是類名小寫;employee
alias:指定新的別名
-->
<!-- <typeAlias type="com.atguigu.mybatis.bean.Employee" alias="emp"/> -->
<!-- 2、package:為某個包下的所有類批量起別名
name:指定包名(為當前包以及下面所有的後代包的每一個類都起一個預設別名(類名小寫),)
-->
<package name="com.atguigu.mybatis.bean"/>
<!-- 3、批量起別名的情況下,使用@Alias註解為某個型別指定新的別名 -->
</typeAliases>
第3種情況:
@Alias("emp")
public class Employee {....}
同時它內建了一些Java型別內建的類型別名。
typeHandlers(型別處理器):
environments(執行環境)介紹(僅做了解):
<!--
4、environments:環境們,mybatis可以配置多種環境 ,default指定使用某種環境。可以達到快速切換環境。
environment:配置一個具體的環境資訊;必須有兩個標籤;id代表當前環境的唯一標識
transactionManager:事務管理器;
type:事務管理器的型別;JDBC(JdbcTransactionFactory) 這個配置直接使用了 JDBC 的提交和回滾設施,它依賴從資料來源獲得的連線來管理事務作用域。|MANAGED(ManagedTransactionFactory) 這個配置幾乎沒做什麼。它從不提交或回滾一個連線,而是讓容器來管理事務的整個生命週期
自定義事務管理器:實現TransactionFactory介面.type指定為全類名
dataSource:資料來源;
type:資料來源型別;UNPOOLED(UnpooledDataSourceFactory) 這個資料來源的實現會每次請求時開啟和關閉連線。
|POOLED(PooledDataSourceFactory) 這種資料來源的實現利用“池”的概念將 JDBC 連線物件組織起來,避免了建立新的連線例項時所必需的初始化和認證時間。
|JNDI(JndiDataSourceFactory) 這個資料來源實現是為了能在如 EJB 或應用伺服器這類容器中使用,容器可以集中或在外部配置資料來源,然後放置一個 JNDI 上下文的資料來源引用。
自定義資料來源:實現DataSourceFactory介面,type是全類名
-->
<environments default="dev_mysql">
<environment id="dev_mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<!--這是 JDBC 驅動的 Java 類全限定名(並不是 JDBC 驅動中可能包含的資料來源類)。 -->
<property name="driver" value="${jdbc.driver}" />
<!--這是資料庫的 JDBC URL 地址。 -->
<property name="url" value="${jdbc.url}" />
<!--登入資料庫的使用者名稱。 -->
<property name="username" value="${jdbc.username}" />
<!--登入資料庫的密碼。 -->
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
databaseIdProvider (多資料庫支援)
<!-- 5、databaseIdProvider:支援多資料庫廠商的;
type="DB_VENDOR":VendorDatabaseIdProvider
作用就是得到資料庫廠商的標識(驅動getDatabaseProductName()),mybatis就能根據資料庫廠商標識來執行不同的sql;
MySQL,Oracle,SQL Server,xxxx
-->
<databaseIdProvider type="DB_VENDOR">
<!-- 為不同的資料庫廠商起別名 -->
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
<property name="SQL Server" value="sqlserver"/>
</databaseIdProvider>
再將新加入的Oracle資料庫的配置資訊寫入properties(需要先將Oracle資料庫連線jar包匯入)
orcl.driver=oracle.jdbc.OracleDriver
orcl.url=jdbc:oracle:thin:@localhost:1521:orcl
orcl.username=scott
orcl.password=123456
配置xml中的執行環境:
<environment id="dev_oracle">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${orcl.driver}" />
<property name="url" value="${orcl.url}" />
<property name="username" value="${orcl.username}" />
<property name="password" value="${orcl.password}" />
</dataSource>
</environment>
</environments>
再將xml檔案中
mappers_sql注射對映:
<!-- 將我們寫好的sql對映檔案(EmployeeMapper.xml)一定要註冊到全域性配置檔案(mybatis-config.xml)中 -->
<!-- 6、mappers:將sql對映註冊到全域性配置中 -->
<mappers>
<!--
mapper:註冊一個sql對映
註冊配置檔案
resource:引用類路徑下的sql對映檔案
mybatis/mapper/EmployeeMapper.xml
url:引用網路路徑或者磁碟路徑下的sql對映檔案
file:///var/mappers/AuthorMapper.xml
<mapper resource="mybatis/mapper/EmployeeMapper.xml"/> -->
<!-- 註冊介面
class:引用(註冊)介面,
1、有sql對映檔案,對映檔名必須和介面同名,並且放在與介面同一目錄下;
2、沒有sql對映檔案,所有的sql都是利用註解寫在介面上;
推薦:
比較重要的,複雜的Dao介面我們來寫sql對映檔案
不重要,簡單的Dao介面為了開發快速可以使用註解;
-->
<!-- <mapper class="com.atguigu.mybatis.dao.EmployeeMapperAnnotation"/> -->
<!-- 批量註冊: -->
<package name="com.atguigu.mybatis.dao"/>
</mappers>
基於註解的抽象類 :
對映檔案(xml)及介面類都放在同一目錄下可能會比較混亂,我們可以
實際上在磁碟上他們仍然是在同一個資料夾內。
MyBatis對映檔案(EmployeeMapper.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.atguigu.mybatis.dao.EmployeeMapper">
<!-- public void addEmp(Employee employee); -->
<!-- parameterType:引數型別,可以省略,
獲取自增主鍵的值:
mysql支援自增主鍵,自增主鍵值的獲取,mybatis也是利用statement.getGenreatedKeys();
useGeneratedKeys="true";使用自增主鍵獲取主鍵值策略
keyProperty;指定對應的主鍵屬性,也就是mybatis獲取到主鍵值以後,將這個值封裝給javaBean的哪個屬性
-->
<insert id="addEmp" parameterType="com.atguigu.mybatis.bean.Employee"
useGeneratedKeys="true" keyProperty="id" databaseId="mysql">
insert into tbl_employee(last_name,email,gender)
values(#{lastName},#{email},#{gender})
</insert>
<!--
獲取非自增主鍵的值:
Oracle不支援自增;Oracle使用序列來模擬自增;
每次插入的資料的主鍵是從序列中拿到的值;如何獲取到這個值;
-->
<insert id="addEmp" databaseId="oracle">
<!--
keyProperty:查出的主鍵值封裝給javaBean的哪個屬性
order="BEFORE":當前sql在插入sql之前執行
AFTER:當前sql在插入sql之後執行
resultType:查出的資料的返回值型別
BEFORE執行順序:(適用於執行之前得知主鍵屬性的值用以執行操作)
先執行selectKey查詢id的sql;查出id值封裝給javaBean的id屬性
在執行插入的sql;就可以取出id屬性對應的值
AFTER執行順序:(適用於執行之後還需要得知主鍵屬性的值)
先執行插入的sql(從序列中取出新值作為id);
再執行selectKey查詢id的sql;
-->
<selectKey keyProperty="id" order="BEFORE" resultType="Integer">
<!-- 編寫查詢主鍵的sql語句 -->
<!-- BEFORE-->
select EMPLOYEES_SEQ.nextval from dual
<!-- AFTER:
select EMPLOYEES_SEQ.currval from dual -->
</selectKey>
<!-- 插入時的主鍵是從序列中拿到的 -->
<!-- BEFORE:-->
insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL)
values(#{id},#{lastName},#{email<!-- ,jdbcType=NULL -->})
<!-- AFTER:
insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL)
values(employees_seq.nextval,#{lastName},#{email}) -->
</insert>
<!-- public void updateEmp(Employee employee); -->
<update id="updateEmp">
update tbl_employee
set last_name=#{lastName},email=#{email},gender=#{gender}
where id=#{id}
</update>
<!-- public void deleteEmpById(Integer id); -->
<delete id="deleteEmpById">
delete from tbl_employee where id=#{id}
</delete>
</mapper>
測試類:
/**
* 測試增刪改
* 1、mybatis允許增刪改直接定義以下型別返回值
* Integer、Long、Boolean、void
* 2、我們需要手動提交資料
* sqlSessionFactory.openSession();===》手動提交
* sqlSessionFactory.openSession(true);===》自動提交
* @throws IOException
*/
@Test
public void test03() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//1、獲取到的SqlSession不會自動提交資料
SqlSession openSession = sqlSessionFactory.openSession();
try{
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
//測試新增
Employee employee = new Employee(null, "jerry4",null, "1");
mapper.addEmp(employee);
System.out.println(employee.getId());
//測試修改
//Employee employee = new Employee(1, "Tom", "[email protected]", "0");
//boolean updateEmp = mapper.updateEmp(employee);
//System.out.println(updateEmp);
//測試刪除
//mapper.deleteEmpById(2);
//2、手動提交資料
openSession.commit();
}finally{
openSession.close();
}
}
引數處理:
單個引數:mybatis不會做特殊處理,
#{引數名/任意名}:取出引數值。
多個引數:mybatis會做特殊處理。
多個引數會被封裝成 一個map,
key:param1...paramN,或者引數的索引也可以
value:傳入的引數值
#{}就是從map中獲取指定的key的值;
異常:
org.apache.ibatis.binding.BindingException:
Parameter 'id' not found.
Available parameters are [1, 0, param1, param2]
操作:
方法:public Employee getEmpByIdAndLastName(Integer id,String lastName);
取值:#{id},#{lastName}
方法一:對映檔案中對應改為:
<!-- public Employee getEmpByIdAndLastName(Integer id,String lastName);-->
<select id="getEmpByIdAndLastName" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee where id = #{param1} and last_name=#{param2}
</select>
【命名引數】:明確指定封裝引數時map的key;@Param("id")
方法二:對應介面改為:
eg:public Employee getEmpByIdAndLastName(@Param("id")Integer id,@Param("lastName")String lastName);
多個引數會被封裝成 一個map,
key:使用@Param註解指定的值
value:引數值
#{指定的key}取出對應的引數值
POJO&Map&TO:
POJO:
如果多個引數正好是我們業務邏輯的資料模型,我們就可以直接傳入pojo;
#{屬性名}:取出傳入的pojo的屬性值
Map:
如果多個引數不是業務模型中的資料,沒有對應的pojo,不經常使用,為了方便,我們也可以傳入map
#{key}:取出map中對應的值
TO:
如果多個引數不是業務模型中的資料,但是經常要使用,推薦來編寫一個TO(Transfer Object)資料傳輸物件
Page{
int index;
int size;
}
傳入map:
首先在介面類中定義一個抽象方法;
public Employee getEmpByMap(Map<String, Object> map);
在對映檔案中加入對應的select語句:
<!-- public Employee getEmpByMap(Map<String, Object> map); -->
<select id="getEmpByMap" resultType="com.atguigu.mybatis.bean.Employee">
select * from ${tableName} where id=${id} and last_name=#{lastName}
</select>
一些思考:
public Employee getEmp(@Param("id")Integer id,String lastName);
取值:id==>#{id/param1} lastName==>#{param2}
public Employee getEmp(Integer id,@Param("e")Employee emp);
取值:id==>#{param1} lastName===>#{param2.lastName/e.lastName}
##特別注意:如果是Collection(List、Set)型別或者是陣列,
也會特殊處理。也是把傳入的list或者陣列封裝在map中。
key:Collection(collection),如果是List還可以使用這個key(list)
陣列(array)
public Employee getEmpById(List<Integer> ids);
取值:取出第一個id的值: #{list[0]}
原始碼分析(沒聽懂):
引數值的獲取:
#{}:可以獲取map中的值或者pojo物件屬性的值;
${}:可以獲取map中的值或者pojo物件屬性的值;
select * from tbl_employee where id=${id} and last_name=#{lastName}
Preparing: select * from tbl_employee where id=2 and last_name=?
區別:
#{}:是以預編譯的形式,將引數設定到sql語句中;PreparedStatement;防止sql注入
${}:取出的值直接拼裝在sql語句中;會有安全問題;
大多情況下,我們去引數的值都應該去使用#{};
原生jdbc不支援佔位符的地方我們就可以使用${}進行取值
比如分表、排序。。。;按照年份分表拆分
select * from ${year}_salary where xxx;
select * from tbl_employee order by ${f_name} ${order}
#{}:更豐富的用法:
規定引數的一些規則:
javaType、 jdbcType、 mode(儲存過程)、 numericScale、
resultMap、 typeHandler、 jdbcTypeName、 expression(未來準備支援的功能);
jdbcType通常需要在某種特定的條件下被設定:
在我們資料為null的時候,有些資料庫可能不能識別mybatis對null的預設處理。比如Oracle(報錯);
JdbcType OTHER:無效的型別;因為mybatis對所有的null都對映的是原生Jdbc的OTHER型別,oracle不能正確處理;
由於全域性配置中:jdbcTypeForNull=OTHER;oracle不支援;兩種辦法
1、#{email,jdbcType=OTHER};
2、jdbcTypeForNull=NULL
<setting name="jdbcTypeForNull" value="NULL"/>
select 返回List:
<!-- public List<Employee> getEmpsByLastNameLike(String lastName); -->
<!--resultType:如果返回的是一個集合,要寫集合中元素的型別 -->
<select id="getEmpsByLastNameLike" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee where last_name like #{lastName}
</select>
測試類中的相關程式碼
List<Employee> like = mapper.getEmpsByLastNameLike("%e%");
for (Employee employee : like) {
System.out.println(employee);
}
select記錄封裝map:
<!--多條 使用id作為map的key -->
<!--public Map<Integer, Employee> getEmpByLastNameLikeReturnMap(String lastName); -->
<select id="getEmpByLastNameLikeReturnMap" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee where last_name like #{lastName}
</select>
<!--單條-->
<!--public Map<String, Object> getEmpByIdReturnMap(Integer id); -->
<select id="getEmpByIdReturnMap" resultType="map">//這裡時因為mybatis為常用Java型別起了別名
select * from tbl_employee where id=#{id}
</select>
介面類中的相應抽象方法定義:
//多條記錄封裝一個map:Map<Integer,Employee>:鍵是這條記錄的主鍵,值是記錄封裝後的javaBean
//@MapKey:告訴mybatis封裝這個map的時候使用哪個屬性作為map的key
@MapKey("id")
public Map<id, Employee> getEmpByLastNameLikeReturnMap(String lastName);
//返回一條記錄的map;key就是列名,值就是對應的值
public Map<String, Object> getEmpByIdReturnMap(Integer id);
(查出資料庫中列名與JavaBean中屬性名不一樣時,有三種可以實現將其封裝的方法 1.查詢語句中寫一個別名 2.符合駝峰命名開啟駝峰命名 3.使用resultMap自定義結果集)
resultMap 自定義結果對映規則:
對應抽象類(EmployeeMapperPlus類):
package com.atguigu.mybatis.dao;
import java.util.List;
import com.atguigu.mybatis.bean.Employee;
public interface EmployeeMapperPlus {
public Employee getEmpById(Integer id);
public Employee getEmpAndDept(Integer id);
public Employee getEmpByIdStep(Integer id);
//根據部門id查詢員工放到list集合裡
public List<Employee> getEmpsByDeptId(Integer deptId);
}
相應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.atguigu.mybatis.dao.EmployeeMapperPlus">
<!--自定義某個javaBean的封裝規則
type:自定義規則的Java型別
id:唯一id方便引用
-->
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MySimpleEmp">
<!--指定主鍵列的封裝規則
id定義主鍵會底層有優化;
column:指定哪一列
property:指定對應的javaBean屬性
-->
<id column="id" property="id"/>
<!-- 定義普通列封裝規則 -->
<result column="last_name" property="lastName"/>
<!-- 其他不指定的列會自動封裝:我們只要寫resultMap就把全部的對映規則都寫上。 -->
<result column="email" property="email"/>
<result column="gender" property="gender"/>
</resultMap>
<!-- resultMap:自定義結果集對映規則; -->
<!-- public Employee getEmpById(Integer id); -->
<select id="getEmpById" resultMap="MySimpleEmp">
select * from tbl_employee where id=#{id}
</select>
</mapper>
關聯物件封裝:
<!--
場景一:
查詢Employee的同時查詢員工對應的部門
employee類中有一個department類 相應employee資料表中對應一個外來鍵指向department表
Employee===Department
一個員工有與之對應的部門資訊;
id last_name gender d_id did dept_name (private Department dept;)
-->
<!--
第一種方式:聯合查詢:級聯屬性封裝結果集
-->
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="gender" property="gender"/>
<result column="did" property="dept.id"/>
<result column="dept_name" property="dept.departmentName"/>
</resultMap>
<!-- public Employee getEmpAndDept(Integer id);-->
<select id="getEmpAndDept" resultMap="MyDifEmp">
SELECT e.id id,e.last_name last_name,e.gender gender,e.d_id d_id,
d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d
WHERE e.d_id=d.id AND e.id=#{id}
</select>
<!--
第二種方式:使用association定義關聯的單個物件的封裝規則;
-->
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp2">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="gender" property="gender"/>
<!-- association可以指定聯合的javaBean物件
property="dept":指定哪個屬性是聯合的物件
javaType:指定這個屬性物件的型別[不能省略]
-->
<!-- 在association裡定義封裝的物件的規則-->
<association property="dept" javaType="com.atguigu.mybatis.bean.Department">
<!-- 注意這裡的Column屬性不能寫成和上面一樣的id,因為預設為第一個id,這裡的 property="id"預設是department下的id-->
<id column="did" property="id"/>
<result column="dept_name" property="departmentName"/>
</association>
</resultMap>
association進行分步查詢:
employMapperPlus.xml檔案:
<!-- 使用association進行分步查詢:一對一
1、先按照員工id查詢員工資訊
2、根據查詢員工資訊中的d_id值去部門表查出部門資訊
3、部門設定到員工中;
-->
<!-- id last_name email gender d_id -->
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpByStep">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
<!-- association定義關聯物件的封裝規則
select:表明當前屬性是呼叫select指定的方法查出的結果
column:指定將哪一列的值傳給這個方法
流程:使用select指定的方法(傳入column指定的這列引數的值)查出物件,並封裝給property指定的屬性
-->
<association property="dept"
select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById"
column="d_id">
</association>
</resultMap>
<!-- public Employee getEmpByIdStep(Integer id);-->
<select id="getEmpByIdStep" resultMap="MyEmpByStep">
select * from tbl_employee where id=#{id}
<if test="_parameter!=null">
and 1=1
</if>
</select>
<!-- 可以使用延遲載入(懶載入);(按需載入)
Employee==>Dept:
我們每次查詢Employee物件的時候,都將一起查詢出來。
部門資訊在我們使用的時候再去查詢;
分段查詢的基礎之上加上兩個配置:
-->(在MyBatis-config.xml中配置)
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
根據需求建立departmentMapper類以及departmentMapper.xml配置檔案:
package com.atguigu.mybatis.dao;
import com.atguigu.mybatis.bean.Department;
public interface DepartmentMapper {
public Department getDeptById(Integer id);
//增強版 在獲取部門id的同時將部門員工查出來
public Department getDeptByIdPlus(Integer id);
//collection分步查詢
public Department getDeptByIdStep(Integer id);
}
departmentMapper.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.atguigu.mybatis.dao.DepartmentMapper">
<!--public Department getDeptById(Integer id); -->
<select id="getDeptById" resultType="com.atguigu.mybatis.bean.Department">
select id,dept_name departmentName from tbl_dept where id=#{id}
</select>
</mapper>
test測試類:
public void test05() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try{
EmployeeMapperPlus mapper = openSession.getMapper(EmployeeMapperPlus.class);
/*Employee empById = mapper.getEmpById(1);
System.out.println(empById);*/
/*Employee empAndDept = mapper.getEmpAndDept(1);
System.out.println(empAndDept);
System.out.println(empAndDept.getDept());*/
Employee employee = mapper.getEmpByIdStep(3);
System.out.println(employee);
//System.out.println(employee.getDept());
System.out.println(employee.getDept());
openSession.close();
}
collection定義關聯集合封裝規則:一對多
對應xml檔案(departmentMapper.xml)配置:
<!--
public class Department {
private Integer id;
private String departmentName;
private List<Employee> emps;
did dept_name || eid last_name email gender
-->
<!--巢狀結果集的方式,使用collection標籤定義關聯的集合型別的屬性封裝規則 -->
<resultMap type="com.atguigu.mybatis.bean.Department" id="MyDept">
<id column="did" property="id"/>
<result column="dept_name" property="departmentName"/>
<!--
collection定義關聯集合型別的屬性的封裝規則
ofType:指定集合裡面元素的型別
注:這裡是將分割號後面的employee中封裝成list集合
-->
<collection property="emps" ofType="com.atguigu.mybatis.bean.Employee">
<!-- 定義這個集合中元素的封裝規則 -->
<id column="eid" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
</collection>
</resultMap>
<!-- public Department getDeptByIdPlus(Integer id); -->
<select id="getDeptByIdPlus" resultMap="MyDept">
SELECT d.id did,d.dept_name dept_name,
e.id eid,e.last_name last_name,e.email email,e.gender gender
FROM tbl_dept d
LEFT JOIN tbl_employee e
ON d.id=e.d_id
WHERE d.id=#{id}
</select>
collection分佈查詢延遲載入:
departmentMapper.xml
<!-- collection:分段查詢 -->
<resultMap type="com.atguigu.mybatis.bean.Department" id="MyDeptStep">
<id column="id" property="id"/>
<id column="dept_name" property="departmentName"/>
<collection property="emps"
select="com.atguigu.mybatis.dao.EmployeeMapperPlus.getEmpsByDeptId"
<!-- column = "id" 為原始,以下為拓展演示案例) -->
column="{deptId=id}" fetchType="lazy"></collection>
</resultMap>
<!-- public Department getDeptByIdStep(Integer id); -->
<select id="getDeptByIdStep" resultMap="MyDeptStep">
select id,dept_name from tbl_dept where id=#{id}
</select>
<!-- 擴充套件:多列的值傳遞過去:
將多列的值封裝map傳遞;
column="{key1=column1,key2=column2}"
fetchType="lazy":表示使用延遲載入;
- lazy:延遲
- eager:立即
-->
EmployMapperPlus.xml檔案配置:
<!--
場景二:
查詢部門的時候將部門對應的所有員工資訊也查詢出來:註釋在DepartmentMapper.xml中
-->
<!-- public List<Employee> getEmpsByDeptId(Integer deptId); -->
<select id="getEmpsByDeptId" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee where d_id=#{deptId}
</select>
對應測試類:
@Test
public void test06() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try{
DepartmentMapper mapper = openSession.getMapper(DepartmentMapper.class);
/*Department department = mapper.getDeptByIdPlus(1);
System.out.println(department);
System.out.println(department.getEmps());*/
Department deptByIdStep = mapper.getDeptByIdStep(1);
System.out.println(deptByIdStep.getDepartmentName());
System.out.println(deptByIdStep.getEmps());
}finally{
openSession.close();
}
}
discriminator鑑別器:
EmployMapperPlus.xml檔案配置:
<!-- <discriminator javaType=""></discriminator>
鑑別器:mybatis可以使用discriminator判斷某列的值,然後根據某列的值改變封裝行為
封裝Employee:
如果查出的是女生:就把部門資訊查詢出來,否則不查詢;
如果是男生,把last_name這一列的值賦值給email;
-->
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpDis">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="email" property="email"/>
<result column="gender" property="gender"/>
<!--
column:指定判定的列名
javaType:列值對應的java型別 -->
<discriminator javaType="string" column="gender">
<!--女生 resultType:指定封裝的結果型別;不能缺少。/resultMap-->
<case value="0" resultType="com.atguigu.mybatis.bean.Employee">
<association property="dept"
select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById"
column="d_id">
</association>
</case>
<!--男生 ;如果是男生,把last_name這一列的值賦值給email; -->
<case value="1" resultType="com.atguigu.mybatis.bean.Employee">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="last_name" property="email"/>
<result column="gender" property="gender"/>
</case>
</discriminator>
</resultMap>
動態sql(動態拼裝sql):
抽象介面類:
package com.atguigu.mybatis.dao;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.atguigu.mybatis.bean.Employee;
public interface EmployeeMapperDynamicSQL {
public List<Employee> getEmpsTestInnerParameter(Employee employee);
//攜帶了哪個欄位查詢條件就帶上這個欄位的值
public List<Employee> getEmpsByConditionIf(Employee employee);
public List<Employee> getEmpsByConditionTrim(Employee employee);
public List<Employee> getEmpsByConditionChoose(Employee employee);
public void updateEmp(Employee employee);
//查詢員工id'在給定集合中的
public List<Employee> getEmpsByConditionForeach(@Param("ids")List<Integer> ids);
public void addEmps(@Param("emps")List<Employee> emps);
}
EmployeeMapperDynamicSQL.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.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
<!--
• if:判斷
• choose (when, otherwise):分支選擇;帶了break的swtich-case
如果帶了id就用id查,如果帶了lastName就用lastName查;只會進入其中一個
• trim 字串擷取(where(封裝查詢條件), set(封裝修改條件))
• foreach 遍歷集合
-->
<!-- 查詢員工,要求,攜帶了哪個欄位查詢條件就帶上這個欄位的值 -->
<!-- public List<Employee> getEmpsByConditionIf(Employee employee); -->
<select id="getEmpsByConditionIf" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee
<!-- where -->
<where>
<!-- test:判斷表示式(OGNL)
OGNL參照PPT或者官方文件。
c:if test
從引數中取值進行判斷
遇見特殊符號應該去寫轉義字元:
&&:&&
"":""
具體可參考 w3cschool html 8859-1符號實體
-->
<if test="id!=null">
id=#{id}
</if>
<if test="lastName!=null && lastName!=""">
and last_name like #{lastName}
</if>
<if test="email!=null and email.trim()!=""">
and email=#{email}
</if>
<!-- ognl會進行字串與數字的轉換判斷 "0"==0 -->
<if test="gender==0 or gender==1">
and gender=#{gender}
</if>
</where>
</select>
<!-- 自定義字串擷取-->
<!--public List<Employee> getEmpsByConditionTrim(Employee employee); -->
<select id="getEmpsByConditionTrim" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee
<!-- 後面多出的and或者or where標籤不能解決
prefix="":字首:trim標籤體中是整個字串拼串 後的結果。
prefix給拼串後的整個字串加一個字首
prefixOverrides="":
字首覆蓋: 去掉整個字串前面多餘的字元
suffix="":字尾
suffix給拼串後的整個字串加一個字尾
suffixOverrides=""
字尾覆蓋:去掉整個字串後面多餘的字元
-->
<!-- 自定義字串的擷取規則 -->
<trim prefix="where" suffixOverrides="and">
<if test="id!=null">
id=#{id} and
</if>
<if test="lastName!=null && lastName!=""">
last_name like #{lastName} and
</if>
<if test="email!=null and email.trim()!=""">
email=#{email} and
</if>
<!-- ognl會進行字串與數字的轉換判斷 "0"==0 -->
<if test="gender==0 or gender==1">
gender=#{gender}
</if>
</trim>
</select>
<!--choose分支選擇-->
<!-- public List<Employee> getEmpsByConditionChoose(Employee employee); -->
<select id="getEmpsByConditionChoose" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee
<where>
<!-- 如果帶了id就用id查,如果帶了lastName就用lastName查;只會進入其中一個 -->
<choose>
<when test="id!=null">
id=#{id}
</when>
<when test="lastName!=null">
last_name like #{lastName}
</when>
<when test="email!=null">
email = #{email}
</when>
<otherwise>
gender = 0
</otherwise>
</choose>
</where>
</select>
<!--public void updateEmp(Employee employee); -->
<update id="updateEmp">
<!-- Set標籤的使用:set 元素會動態地在行首插入 SET 關鍵字,並會刪掉額外的逗號 -->
update tbl_employee
<set>
<if test="lastName!=null">
last_name=#{lastName},
</if>
<if test="email!=null">
email=#{email},
</if>
<if test="gender!=null">
gender=#{gender}
</if>
</set>
where id=#{id}
<!--
Trim:更新拼串
update tbl_employee
<trim prefix="set" suffixOverrides=",">
<if test="lastName!=null">
last_name=#{lastName},
</if>
<if test="email!=null">
email=#{email},
</if>
<if test="gender!=null">
gender=#{gender}
</if>
</trim>
where id=#{id} -->
</update>
<!-- foreach遍歷集合-->
<!--public List<Employee> getEmpsByConditionForeach(List<Integer> ids); -->
<select id="getEmpsByConditionForeach" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee
<!--
collection:指定要遍歷的集合:
list型別的引數會特殊處理封裝在map中,map的key就叫list
item:將當前遍歷出的元素賦值給指定的變數
separator:每個元素之間的分隔符
open:遍歷出所有結果拼接一個開始的字元
close:遍歷出所有結果拼接一個結束的字元
index:索引。遍歷list的時候是index就是索引,item就是當前值
遍歷map的時候index表示的就是map的key,item就是map的值
#{變數名}就能取出變數的值也就是當前遍歷出的元素
-->
<foreach collection="ids" item="item_id" separator=","
open="where id in(" close=")">
#{item_id}
</foreach>
</select>
</mapper>
測試類:
@Test
public void testDynamicSql() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try{
EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
//select * from tbl_employee where id=? and last_name like ?
//測試if\where
Employee employee = new Employee(1, "Admin", null, null);
/* List<Employee> emps = mapper.getEmpsByConditionIf(employee );
for (Employee emp : emps) {
System.out.println(emp);
}*/
//查詢的時候如果某些條件沒帶可能sql拼裝會有問題
//1、給where後面加上1=1,以後的條件都and xxx.
//2、mybatis使用where標籤來將所有的查詢條件包括在內。mybatis就會將where標籤中拼裝的sql,多出來的and或者or去掉
//where只會去掉第一個多出來的and或者or。
//測試Trim
/*List<Employee> emps2 = mapper.getEmpsByConditionTrim(employee);
for (Employee emp : emps2) {
System.out.println(emp);
}*/
//測試choose
/*List<Employee> list = mapper.getEmpsByConditionChoose(employee);
for (Employee emp : list) {
System.out.println(emp);
}*/
//測試set標籤
/*mapper.updateEmp(employee);
openSession.commit();*/
List<Employee> list = mapper.getEmpsByConditionForeach(Arrays.asList(1,2));
for (Employee emp : list) {
System.out.println(emp);
}
}finally{
openSession.close();
}
}
foreach批量插入:
<!-- 批量儲存 -->
<!--public void addEmps(@Param("emps")List<Employee> emps); -->
<insert id="addEmps">
insert into tbl_employee(
<include refid="insertColumn"></include>
)
values
<foreach collection="emps" item="emp" separator=",">
(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
</foreach>
<!--MySQL下批量儲存:可以foreach遍歷 mysql支援values(),(),()語法-->
</insert><!-- -->
<!-- 這種方式需要資料庫連線屬性allowMultiQueries=true;(在dbconfig.properties裡 jdbc.url里加入)
這種分號分隔多個sql可以用於其他的批量操作(刪除,修改) -->
<!-- <insert id="addEmps">
<foreach collection="emps" item="emp" separator=";">
insert into tbl_employee(last_name,email,gender,d_id)
values(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
</foreach>
</insert> -->
<!-- Oracle資料庫批量儲存:
Oracle不支援values(),(),()
Oracle支援的批量方式
1、多個insert放在begin - end裡面
begin
insert into employees(employee_id,last_name,email)
values(employees_seq.nextval,'test_001','[email protected]');
insert into employees(employee_id,last_name,email)
values(employees_seq.nextval,'test_002','[email protected]');
end;
2、利用中間表:
insert into employees(employee_id,last_name,email)
select employees_seq.nextval,lastName,email from(
select 'test_a_01' lastName,'test_a_e01' email from dual
union
select 'test_a_02' lastName,'test_a_e02' email from dual
union
select 'test_a_03' lastName,'test_a_e03' email from dual
)
-->
<insert id="addEmps" databaseId="oracle">
<!-- oracle第一種批量方式 -->
<!-- <foreach collection="emps" item="emp" open="begin" close="end;">
insert into employees(employee_id,last_name,email)
values(employees_seq.nextval,#{emp.lastName},#{emp.email});
</foreach> -->
<!-- oracle第二種批量方式 -->
insert into employees(
<!-- 引用外部定義的sql -->
<include refid="insertColumn">
<property name="testColomn" value="abc"/>
</include>
)
<foreach collection="emps" item="emp" separator="union"
open="select employees_seq.nextval,lastName,email from("
close=")">
select #{emp.lastName} lastName,#{emp.email} email from dual
</foreach>
</insert>
<!--內建引數-->
<!-- 兩個內建引數:
不只是方法傳遞過來的引數可以被用來判斷,取值。。。
mybatis預設還有兩個內建引數:
_parameter:代表整個引數
單個引數:_parameter就是這個引數
多個引數:引數會被封裝為一個map;_parameter就是代表這個map
_databaseId:如果配置了databaseIdProvider標籤。
_databaseId就是代表當前資料庫的別名oracle
-->
<!--public List<Employee> getEmpsTestInnerParameter(Employee employee); -->
<select id="getEmpsTestInnerParameter" resultType="com.atguigu.mybatis.bean.Employee">
<!-- bind:可以將OGNL表示式的值繫結到一個變數中,方便後來引用這個變數的值 -->
<bind name="_lastName" value="'%'+lastName+'%'"/>
<if test="_databaseId=='mysql'">
select * from tbl_employee
<!-- "_parameter!=null"即可保證查詢的employee不為空-->
<if test="_parameter!=null">
where last_name like #{lastName}
</if>
</if>
<if test="_databaseId=='oracle'">
select * from employees
<if test="_parameter!=null">
where last_name like #{_parameter.lastName}
</if>
</if>
</select>
<!--
抽取可重用的sql片段。方便後面引用
1、sql抽取:經常將要查詢的列名,或者插入用的列名抽取出來方便引用
2、include來引用已經抽取的sql:
3、include還可以自定義一些property,sql標籤內部就能使用自定義的屬性
include-property:取值的正確方式${prop},
#{不能使用這種方式}
-->
<sql id="insertColumn">
<if test="_databaseId=='oracle'">
employee_id,last_name,email
</if>
<if test="_databaseId=='mysql'">
last_name,email,gender,d_id
</if>
</sql>
測試類:
@Test
public void testBatchSave() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try{
EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
List<Employee> emps = new ArrayList<>();
emps.add(new Employee(null, "smith0x1", "[email protected]", "1",new Department(1)));
emps.add(new Employee(null, "allen0x1", "[email protected]", "0",new Department(1)));
mapper.addEmps(emps);
openSession.commit();
}finally{
openSession.close();
}
}
MyBatis快取機制:
mybatis作為一個持久化的框架定義了二級快取。
一級快取:
* 一級快取:(本地快取):sqlSession級別的快取。一級快取是一直開啟的;SqlSession級別的一個Map
* 與資料庫同一次會話期間查詢到的資料會放在本地快取中。
* 以後如果需要獲取相同的資料,直接從快取中拿,沒必要再去查詢資料庫;
*
* 一級快取失效情況(沒有使用到當前一級快取的情況,效果就是,還需要再向資料庫發出查詢):
* 1、sqlSession不同。
* 2、sqlSession相同,查詢條件不同.(當前一級快取中還沒有這個資料)
* 3、sqlSession相同,兩次查詢之間執行了增刪改操作(這次增刪改可能對當前資料有影響)
* 4、sqlSession相同,手動清除了一級快取(快取清空)
測試類:
@Test
public void testFirstLevelCache() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try{
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Employee emp01 = mapper.getEmpById(1);
System.out.println(emp01);
Employee emp02 = mapper.getEmpById(1);
System.out.println(emp01==emp02);//true
一級快取失效的情況:
* 一級快取失效情況(沒有使用到當前一級快取的情況,效果就是,還需要再向資料庫發出查詢):
* 1、sqlSession不同。
* 2、sqlSession相同,查詢條件不同.(當前一級快取中還沒有這個資料)
* 3、sqlSession相同,兩次查詢之間執行了增刪改操作(這次增刪改可能對當前資料有影響)
* 4、sqlSession相同,手動清除了一級快取(快取清空)
//xxxxx
//1、sqlSession不同。
//SqlSession openSession2 = sqlSessionFactory.openSession();
//EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
//System.out.println(emp01==emp02);//false
//2、sqlSession相同,查詢條件不同
//Employee emp03 = mapper.getEmpById(3);
//System.out.println(emp01==emp0);//false
//3、sqlSession相同,兩次查詢之間執行了增刪改操作(這次增刪改可能對當前資料有影響)
//mapper.addEmp(new Employee(null, "testCache", "cache", "1"));
//System.out.println("資料新增成功");
//Employee emp02 = mapper.getEmpById(1);
//System.out.println(emp02);
//System.out.println(emp01==emp02);//false
//4、sqlSession相同,手動清除了一級快取(快取清空)
//openSession.clearCache();
//Employee emp02 = mapper.getEmpById(1);
//System.out.println(emp02);
//System.out.println(emp01==emp02);//false
//openSession2.close();
}finally{
openSession.close();
}
}
}
二級快取:
* 二級快取:(全域性快取):基於namespace級別的快取:一個namespace對應一個二級快取:
* 工作機制:
* 1、一個會話,查詢一條資料,這個資料就會被放在當前會話的一級快取中;
* 2、如果會話關閉;一級快取中的資料會被儲存到二級快取中;新的會話查詢資訊,就可以參照二級快取中的內容;
* 3、sqlSession===EmployeeMapper==>Employee
* DepartmentMapper===>Department
* 不同namespace查出的資料會放在自己對應的快取中(map)
* 效果:資料會從二級快取中獲取
* 查出的資料都會被預設先放在一級快取中。
* 只有會話提交或者關閉以後,一級快取中的資料才會轉移到二級快取中
* 使用:
* 1)、開啟全域性二級快取配置:<setting name="cacheEnabled" value="true"/>
* 2)、去mapper.xml中配置使用二級快取:
* <cache></cache>
* 3)、我們的POJO需要實現序列化介面(department類和employee類)
*
* 和快取有關的設定/屬性:
* 1)、cacheEnabled=true:false:關閉快取(二級快取關閉)(一級快取一直可用的)
* 2)、每個select標籤都有useCache="true":
* false:不使用快取(一級快取依然使用,二級快取不使用)
* 3)、【每個增刪改標籤的:flushCache="true":(一級二級都會清除)】
* 增刪改執行完成後就會清楚快取;
* 測試:flushCache="true":一級快取就清空了;二級也會被清除;
* 查詢標籤:flushCache="false":
* 如果flushCache=true;每次查詢之後都會清空快取;快取是沒有被使用的;
* 4)、sqlSession.clearCache();只是清除當前session的一級快取;與二級無關。
* 5)、localCacheScope:本地快取作用域:(一級快取SESSION);當前會話的所有資料儲存在會話快取中;
* STATEMENT:可以禁用一級快取;
*
departmentMapper.xml中的檔案配置:
<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"></cache>
<!--
eviction:快取的回收策略:
• LRU – 最近最少使用的:移除最長時間不被使用的物件。
• FIFO – 先進先出:按物件進入快取的順序來移除它們。
• SOFT – 軟引用:移除基於垃圾回收器狀態和軟引用規則的物件。
• WEAK – 弱引用:更積極地移除基於垃圾收集器狀態和弱引用規則的物件。
• 預設的是 LRU。
flushInterval:快取重新整理間隔
快取多長時間清空一次,預設不清空,設定一個毫秒值
readOnly:是否只讀:
true:只讀;mybatis認為所有從快取中獲取資料的操作都是隻讀操作,不會修改資料。
mybatis為了加快獲取速度,直接就會將資料在快取中的引用交給使用者。不安全,速度快
false:非只讀:mybatis覺得獲取的資料可能會被修改。
mybatis會利用序列化&反序列的技術克隆一份新的資料給你。安全,速度慢
size:快取存放多少元素;
type="":指定自定義快取的全類名;
實現Cache介面即可;
-->
測試類:
@Test
public void testSecondLevelCache02() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
SqlSession openSession2 = sqlSessionFactory.openSession();
try{
//1、
DepartmentMapper mapper = openSession.getMapper(DepartmentMapper.class);
DepartmentMapper mapper2 = openSession2.getMapper(DepartmentMapper.class);
Department deptById = mapper.getDeptById(1);
System.out.println(deptById);
openSession.close();
Department deptById2 = mapper2.getDeptById(1);
System.out.println(deptById2);
openSession2.close();
//第二次查詢是從二級快取中拿到的資料,並沒有傳送新的sql
}finally{
}
}
第三方cache包:
*第三方快取整合:
* 1)、匯入第三方快取包即可;
* 2)、匯入與第三方快取整合的適配包;官方有;
* 3)、mapper.xml中使用自定義快取
* <cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
首先匯入這三個包:
修改相應的xxxMapper.xml檔案
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
配置ehcache.xml檔案
<?xml version="1.0" encoding="UTF-8"?>
-<ehcache xsi:noNamespaceSchemaLocation="../config/ehcache.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- 屬性說明: l diskStore:指定資料在磁碟中的儲存位置。 l defaultCache:當藉助CacheManager.add("demoCache")建立Cache時,EhCache便會採用<defalutCache/>指定的的管理策略 以下屬性是必須的: l maxElementsInMemory - 在記憶體中快取的element的最大數目 l maxElementsOnDisk - 在磁碟上快取的element的最大數目,若是0表示無窮大 l eternal - 設定快取的elements是否永遠不過期。如果為true,則快取的資料始終有效,如果為false那麼還要根據timeToIdleSeconds,timeToLiveSeconds判斷 l overflowToDisk - 設定當記憶體快取溢位的時候是否將過期的element快取到磁碟上 以下屬性是可選的: l timeToIdleSeconds - 當快取在EhCache中的資料前後兩次訪問的時間超過timeToIdleSeconds的屬性取值時,這些資料便會刪除,預設值是0,也就是可閒置時間無窮大 l timeToLiveSeconds - 快取element的有效生命期,預設是0.,也就是element存活時間無窮大 diskSpoolBufferSizeMB 這個引數設定DiskStore(磁碟快取)的快取區大小.預設是30MB.每個Cache都應該有自己的一個緩衝區. l diskPersistent - 在VM重啟的時候是否啟用磁碟儲存EhCache中的資料,預設是false。 l diskExpiryThreadIntervalSeconds - 磁碟快取的清理執行緒執行間隔,預設是120秒。每個120s,相應的執行緒會進行一次EhCache中資料的清理工作 l memoryStoreEvictionPolicy - 當記憶體快取達到最大,有新的element加入的時候, 移除快取中element的策略。預設是LRU(最近最少使用),可選的有LFU(最不常使用)和FIFO(先進先出) -->
<!-- 磁碟儲存路徑 -->
<diskStore path="D:\44\ehcache"/>
<defaultCache
memoryStoreEvictionPolicy="LRU"
diskExpiryThreadIntervalSeconds="120"
timeToLiveSeconds="120"
timeToIdleSeconds="120"
overflowToDisk="true"
eternal="false"
maxElementsOnDisk="10000000"
maxElementsInMemory="1">
</defaultCache>
</ehcache>
mybatis工作原理圖:
MyBatis整合Spring:
這裡由於還沒學spring放到後續!
逆向工程:
首先下載generator,解壓壓縮包將其匯入:
配置mgb.xml檔案:
<?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>
<!--
targetRuntime="MyBatis3Simple":生成簡單版的CRUD
MyBatis3:豪華版
-->
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- jdbcConnection:指定如何連線到目標資料庫 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true"
userId="root"
password="123456">
</jdbcConnection>
<!-- -->
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- javaModelGenerator:指定javaBean的生成策略
targetPackage="test.model":目標包名
targetProject="\MBGTestProject\src":目標工程
-->
<javaModelGenerator targetPackage="com.atguigu.mybatis.bean"
targetProject=".\src">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- sqlMapGenerator:sql對映生成策略: -->
<sqlMapGenerator targetPackage="com.atguigu.mybatis.dao"
targetProject=".\conf">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- javaClientGenerator:指定mapper介面所在的位置 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.mybatis.dao"
targetProject=".\src">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- 指定要逆向分析哪些表:根據表要建立javaBean -->
<table tableName="tbl_dept" domainObjectName="Department"></table>
<table tableName="tbl_employee" domainObjectName="Employee"></table>
</context>
</generatorConfiguration>
用程式碼方式讓generrator跑起來:
@Test
public void testMbg() throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("mbg.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
callback, warnings);
myBatisGenerator.generate(null);
}
測試MyBatis簡單版:
@Test
public void testMyBatis3Simple() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try{
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
List<Employee> list = mapper.selectByExample(null);
for (Employee employee : list) {
System.out.println(employee.getId());
}
}finally{
openSession.close();
}
}
測試MyBatis3豪華版:
@Test
public void testMyBatis3() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
try{
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
//xxxExample就是封裝查詢條件的
//1、查詢所有
//List<Employee> emps = mapper.selectByExample(null);
//2、查詢員工名字中有e字母的,和員工性別是1的
//封裝員工查詢條件的example
EmployeeExample example = new EmployeeExample();
//建立一個Criteria,這個Criteria就是拼裝查詢條件
//select id, last_name, email, gender, d_id from tbl_employee
//WHERE ( last_name like ? and gender = ? ) or email like "%e%"
Criteria criteria = example.createCriteria();
criteria.andLastNameLike("%e%");
criteria.andGenderEqualTo("1");
Criteria criteria2 = example.createCriteria();
criteria2.andEmailLike("%e%");
example.or(criteria2);
List<Employee> list = mapper.selectByExample(example);
for (Employee employee : list) {
System.out.println(employee.getId());
}
}finally{
openSession.close();
}
}
執行原理(沒有聽懂,已放後續補):