本文為動力節點2020MyBatis筆記整理,視頻地址為https://www.bilibili.com/video/BV185411s7Ry?from=search&seid=5830402177484068371。
王鶴老師的筆記可自行去動力節點官網下載。
1 介紹
Java WEB 通常分為三層,即表示層,業務邏輯層,數據訪問層。
三層的職責
-
界面層(表示層,視圖層):主要功能是接受用戶的數據,顯示請求的處理結果。使用 web 頁面和用戶交互,手機 app 也就是表示層的,用戶在 app 中操作,業務邏輯在服務器端處理。
-
業務邏輯層:接收表示傳遞過來的數據,檢查數據,計算業務邏輯,調用數據訪問層獲取數據。
-
數據訪問層:與數據庫打交道。主要實現對數據的增、刪、改、查。將存儲在數據庫中的數據提交給業務層,同時將業務層處理的數據保存到數據庫
具體過程為:用戶---> 界面層(Spring MVC)--->業務邏輯層(Spring)--->數據訪問層(MyBatis)--->DB 數據庫。
MyBatis 框架:
MyBatis 是一個優秀的基於 java 的持久層框架,內部封裝了 jdbc,開發者只需要關注 sql 語句本身,而不需要處理加載驅動、創建連接、創建 statement、關閉連接,資源等繁雜的過程。
MyBatis 通過 xml 或注解兩種方式將要執行的各種 sql 語句配置起來,並通過 java 對象和 sql 的動態參數進行映射生成最終執行的 sql 語句,最后由 mybatis 框架執行 sql 並將結果映射為 java 對象並返回。
2 快速入門
對於MyBatis項目來說,除了maven本身的pom.xml以外,還有主配置文件mybatis-config.xml,通常放在Resource目錄下;以及各個Dao接口對應的在同級目錄下且同名的xml映射文件。在主配置文件中,可以設置數據源,事務,別名,日志,分頁以及映射器位置,在Dao對應的映射文件中,通常是寫相應的SQL語句來實現Dao的各種功能。
2.1 操作步驟(P9)
2.1.1 首先創建maven
(1)創建maven:New Project/Module->選擇Maven,打鈎Create from archetype,選擇 :maven-archetype-quickstart,next->輸入Name/Location,點開Artifact Coordinates,輸入相應Id。
(2)等待加載完成后,在src/main上右擊,產生resources目錄,resources下面的資源在編譯后在target/classes下面。
2.1.2 接着會做一些配置
(1)在pom.xml中,修改properties中的1.7為1.8,刪除maven原有的build,加入maven的依賴,包括mybatis和mysql驅動,以及一個掃描src/main/java目錄下的各種資源放入編譯后的target下的classes
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目錄-->
<includes><!--包括目錄下的.properties,.xml 文件都會掃描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
(2)創建Dao接口以及涉及到的Bean對象
(3)創建mapper文件,也叫sql映射文件,是一個xml:寫sql語句的,和接口中方法對應的sql語句。
<?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.bjpowernode.dao.StudentDao">
<!--
select:表示查詢操作。
id: 你要執行的sql語法的唯一標識, mybatis會使用這個id的值來找到要執行的sql語句
可以自定義,但是要求你使用接口中的方法名稱。
resultType:表示結果類型的, 是sql語句執行后得到ResultSet,遍歷這個ResultSet得到java對象的類型。
值寫的類型的全限定名稱
-->
<select id="selectStudents" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student order by id
</select>
<!--插入操作-->
<insert id="insertStudent">
insert into student values(#{id},#{name},#{email},#{age})
</insert>
</mapper>
<!--
sql映射文件(sql mapper): 寫sql語句的, mybatis會執行這些sql
1.指定約束文件
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
mybatis-3-mapper.dtd是約束文件的名稱, 擴展名是dtd的。
2.約束文件作用: 限制,檢查在當前文件中出現的標簽,屬性必須符合mybatis的要求。
3.mapper 是當前文件的根標簽,必須的。
namespace:叫做命名空間,唯一值的, 可以是自定義的字符串。
要求你使用dao接口的全限定名稱。
4.在當前文件中,可以使用特定的標簽,表示數據庫的特定操作。
<select>:表示執行查詢,select語句
<update>:表示更新數據庫的操作, 就是在<update>標簽中 寫的是update sql語句
<insert>:表示插入, 放的是insert語句
<delete>:表示刪除, 執行的delete語句
-->
(4)創建mybatis的一個主配置文件,也是xml,放在resources下,1)連接數據庫;2)指定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">
<configuration>
<!--settings:控制mybatis全局行為-->
<settings>
<!--設置mybatis輸出日志-->
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
<!--環境配置: 數據庫的連接信息
default:必須和某個environment的id值一樣。
告訴mybatis使用哪個數據庫的連接信息。也就是訪問哪個數據庫
-->
<environments default="mydev">
<!-- environment : 一個數據庫信息的配置, 環境
id:一個唯一值,自定義,表示環境的名稱。
-->
<environment id="mydev">
<!--
transactionManager :mybatis的事務類型
type: JDBC(表示使用jdbc中的Connection對象的commit,rollback做事務處理)
-->
<transactionManager type="JDBC"/>
<!--
dataSource:表示數據源,連接數據庫的
type:表示數據源的類型, POOLED表示使用連接池
-->
<dataSource type="POOLED">
<!--
driver, user, username, password 是固定的,不能自定義。
-->
<!--數據庫的驅動類名-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--連接數據庫的url字符串-->
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<!--訪問數據庫的用戶名-->
<property name="username" value="root"/>
<!--密碼-->
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- sql mapper(sql映射文件)的位置-->
<mappers>
<!--一個mapper標簽指定一個文件的位置。
從類路徑開始的路徑信息。 target/clasess(類路徑)
-->
<mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
<!--<mapper resource="com/bjpowernode/dao/SchoolDao.xml" />-->
</mappers>
</configuration>
<!--
mybatis的主配置文件: 主要定義了數據庫的配置信息, sql映射文件的位置
1. 約束文件
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
mybatis-3-config.dtd:約束文件的名稱
2. configuration 根標簽。
-->
(5)使用mybatis的對象SqlSession,通過他的方法執行sql語句。
@Test
public void testSelect() throws Exception{
//1.mybatis 主配置文件
String config = "mybatis-config.xml";
//2.讀取配置文件
InputStream in = Resources.getResourceAsStream(config);
//3.創建 SqlSessionFactory 對象,目的是獲取 SqlSession
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//4.獲取 SqlSession,SqlSession 能執行 sql 語句
SqlSession session = factory.openSession();
//5.執行 SqlSession 的 selectList()
List<Student> studentList = session.selectList("com.bjpowernode.dao.StudentDao.selectStudents");
//6.循環輸出查詢結果
studentList.forEach( student -> System.out.println(student));
//7.關閉 SqlSession,釋放資源
session.close();
}
2.2 在編譯的target目錄下面缺少xml的解決方式(P11)
事先做的配置
1.resource文件夾,前面需要有相應的標識,沒有的話,右鍵-Mark Directory as
2.在pom.xml文件中的<build><resources>...</resources></build>放置resource,用於掃描並將src/main/java的相應資源導入。(見操作步驟)
解決方式
1.右邊的maven,先clean,然后compile
2.上面的Build-ReBuild Project
3.上邊的File-Invalidate Caches/Restart,再點一次。
4.將sql映射文件和主配置文件直接拷貝到target目錄下面。
2.3 日志的輸出
在mybatis.xml的<configuration>后面添加
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
2.4 注意事項
mybatis默認非自動提交事務,查詢不需要提交,而insert/update/delete,需要提交,sqlSession.commit();
2.5對各個對象的分析
Resource類
Resources 類,顧名思義就是資源,用於讀取資源文件。其有很多方法通過加載並解析資源文件,返回不同類型的 IO 流對象。
SqlSessionFactoryBuilder類
SqlSessionFactory 的 創 建 , 需 要 使 用 SqlSessionFactoryBuilder 對 象 的 build() 方 法 。 由於SqlSessionFactoryBuilder 對象在創建完工廠對象后,就完成了其歷史使命,即可被銷毀。所以,一般會將該 SqlSessionFactoryBuilder 對象創建為一個方法內的局部對象,方法結束,對象銷毀。
SqlSessionFactory接口
SqlSessionFactory 接口對象是一個重量級對象(系統開銷大的對象),是線程安全的,所以一個應用只需要一個該對象即可。創建 SqlSession 需要使用 SqlSessionFactory 接口的的 openSession()方法。
➢ openSession(true):創建一個有自動提交功能的 SqlSession
➢ openSession(false):創建一個非自動提交功能的 SqlSession,需手動提交
➢ openSession():同 openSession(false)
SqlSession接口
SqlSession 接口對象用於執行持久化操作。一個 SqlSession 對應着一次數據庫會話,一次會話以SqlSession 對象的創建開始,以 SqlSession 對象的關閉結束。
SqlSession 接口對象是線程不安全的,所以每次數據庫會話結束前,需要馬上調用其 close()方法,將其關閉。再次需要會話,再次創建。 SqlSession 在方法內部創建,使用完畢后關閉。
2.6 工具類
通過該工具類的靜態方法可以方便獲取SqlSession。
public class MyBatisUtils {
private static SqlSessionFactory factory = null;
static {
String config="mybatis.xml"; // 需要和你的項目中的文件名一樣
try {
InputStream in = Resources.getResourceAsStream(config);
//創建SqlSessionFactory對象,使用SqlSessionFactoryBuild
factory = new SqlSessionFactoryBuilder().build(in);
} catch (IOException e) {
e.printStackTrace();
}
}
//獲取SqlSession的方法
public static SqlSession getSqlSession() {
SqlSession sqlSession = null;
if( factory != null){
sqlSession = factory.openSession();// 非自動提交事務
}
return sqlSession;
}
}
3 MyBatis DAO代理
3.1兩種sql的執行方式
第一類是前面的方法,SqlSession直接執行selectList/update/delete/insert之類操作;
第二類是先通過SqlSession的getMapper()獲取接口Dao的實現類,然后調用接口的方法。原理是動態代理。
以select為例解釋,第一種是通過SqlSession直接執行selectList來獲取數據,第二種是SqlSession首先獲取一個StudentDao的一個實現類,該實現類可以直接調用selectStudents獲取數據。
SqlSession session = MyBatisUtil.getSqlSession();
List<Student> studentList = session.selectList("com.bjpowernode.dao.StudentDao.selectStudents");
StudentDao studentDao = MyBatisUtil.getSqlSession().getMapper(StudentDao.class);
List<Student> studentList = studentDao.selectStudents();
3.2 參數的理解
3.2.1 parameterType
parameterType表示傳入的參數類型,可以省略。
3.2.2 傳入的參數在SQL語句中的使用
(1)如果傳入的是一個簡單類型(java 基本類型和 String),在SQL中,可以用#{任意字符}
<select id="selectById" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where id=#{studentId}
</select>
#{studentId} , studentId 是自定義的變量名稱,和方法參數名無關。
(2)傳入多個參數,使用@Param
接口方法:
List<Student> selectMultiParam(@Param("personName") String name,@Param("personAge") int age);
mapper 文件:
<select id="selectMultiParam" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{personName} or age
=#{personAge}</select>
(3)傳入一個對象,#{ property,javaType=java 中數據類型名,jdbcType=數據類型名稱 },簡寫為 #{ property }
創建保存參數值的對象 QueryParam
package com.bjpowernode.vo;
public class QueryParam {
private String queryName;
private int queryAge;
//set ,get 方法}
接口方法:
List<Student> selectMultiObject(QueryParam queryParam);
mapper 文件:
<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student where name=#{queryName} or age
=#{queryAge}
</select>
(4)多個參數還可以按位置或者使用map
3.2.3 #和$的區別
1. #使用 ?在sql語句中做占位的, 使用PreparedStatement執行sql,效率高
2. #能夠避免sql注入,更安全。
3. $不使用占位符,是字符串連接方式,使用Statement對象執行sql,效率低
4. $有sql注入的風險,缺乏安全性。
5. $:可以替換表名或者列名
3.2.4 resultType和resultMap
兩者選一,resultMap主要用於表的列和對象屬性不匹配。
<resultMap id="student2Map" type="com.bjpowernode.domain.Student2">
<!-- 主鍵字段使用 id -->
<id column="id" property="id2" />
<!--非主鍵字段使用 result-->
<result column="name" property="name2"/>
<result column="email" property="email2" />
<result column="age" property="age2" />
</resultMap>
<select id="selectStudents2" resultMap="student2Map">
select id,name,email,age from student order by id
</select>
3.2.5 模糊like
例 1: java 代碼中提供要查詢的 “%力%”
接口方法:
List<Student> selectLikeFirst(String name);
mapper 文件:
<select id="selectLikeFirst" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student
where name like #{studentName}
</select>
測試方法:
@Test
public void testSelectLikeOne(){
String name="%力%";
List<Student> stuList = studentDao.selectLikeFirst(name);
stuList.forEach( stu -> System.out.println(stu));
}
例 2:mapper 文件中使用 like name "%" #{xxx} "%"
接口方法:
List<Student> selectLikeSecond(String name);
mapper 文件:
<select id="selectLikeSecond" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student
where name like "%" #{studentName} "%"
</select>
測試方法:
@Test
public void testSelectLikeSecond(){
String name="力";
List<Student> stuList = studentDao.selectLikeSecond(name);
stuList.forEach( stu -> System.out.println(stu));
}
4 動態SQL
對於 sql 中的"<",一定要換成"<"。
動態 SQL 相當於會變化的 SQL,主要包括<if>,<where>,<foreach>和代碼片段。
if 可以在滿足條件時執行相應功能,where主要用於包裝if,去掉多余的and/or,foreach是對於一個可以遍歷的集合進行輸出,代碼片段表示代碼的重用功能。
示例:
4.1 if 和 where
<select id="selectStudentWhere" resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student
<where>
<if test="name != null and name !='' ">
and name = #{name}
</if>
<if test="age > 0 ">
and age > #{age}
</if>
</where>
</select>
4.2 foreach
<!--說明-->
<foreach collection="集合類型" open="開始的字符" close="結束的字符"
item="集合中的成員" separator="集合成員之間的分隔符">
#{item 的值}
</foreach>
<!--示例-->
<select id="selectStudentForList"
resultType="com.bjpowernode.domain.Student">
select id,name,email,age from student
<if test="list !=null and list.size > 0 ">
where id in
<foreach collection="list" open="(" close=")"
item="stuid" separator=",">
#{stuid}
</foreach>
</if>
</select>
4.3 代碼片段,重用
<sql/>標簽用於定義 SQL 片斷,以便其它 SQL 標簽復用。而其它標簽使用該 SQL 片斷,需要使用<include/>子標簽。
<sql id="studentSql">
select id,name,email,age from student
</sql> <select id="selectStudentSqlFragment"
resultType="com.bjpowernode.domain.Student">
<!-- 引用 sql 片段 -->
<include refid="studentSql"/>
<if test="list !=null and list.size > 0 ">
where id in
<foreach collection="list" open="(" close=")"
item="stuobject" separator=",">
#{stuobject.id}
</foreach>
</if>
</select>
5 配置文件
5.1 主配置文件
之前項目中使用的 mybatis.xml 是主配置文件。
主配置文件特點:
1.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">
2.根元素,<configuration>
3.主要包含內容:
定義別名
數據源
mapper 文件
5.2 dataSource
在主配置文件中配置,包括下面三種
-
UNPOOLED 不使用連接池的數據源,MyBatis 會創建 UnpooledDataSource 實例
-
POOLED 使用連接池的數據源,MyBatis 會創建 PooledDataSource 實例
-
JNDI 使用 JNDI 實現的數據源,MyBatis 會從 JNDI 服務上查找 DataSource 實例
<dataSource type="POOLED">
<!--連接數據庫的四個要素-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/ssm?charset=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
5.3 事務
使用位置,<transactionManager type="JDBC"/>
-
JDBC,使用 JDBC 的事務管理機制。默認不自動提交,需要手動提交。
-
MANAGED,由容器來管理事務的整個生命周期(如 Spring 容器)。
5.4 使用數據庫屬性配置文件
將寫在dataSource中數據庫四個要素抽取到一個文件中,主文件中換成${文件名.具體name}。
<dataSource type="POOLED">
<!--使用 properties 文件: 語法 ${key}-->
<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>
5.5 mapper(映射器)
1.<mapper resource=" " />
使用相對於類路徑的資源,從 classpath 路徑查找文件,
例如:<mapper resource="com/bjpowernode/dao/StudentDao.xml" />
2. <package name=""/>
指定包下的所有 Dao 接口
如:<package name="com.bjpowernode.dao"/>
注意:此種方法要求 Dao 接口名稱和 mapper 映射文件名稱相同,且在同一個目錄中。
6 分頁
使用插件 PageHelper,對應配置如下:
- 在pom.xml中
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
- 在mybatis主配置文件中,<environments>之前加入
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor" />
</plugins>
用法
@Test
public void testSelect() throws IOException {
//獲取第 1 頁,3 條內容
PageHelper.startPage(1,3);
List<Student> studentList = studentDao.selectStudents();
studentList.forEach( stu -> System.out.println(stu));
}