前言:配合狂神老師的教學視頻使用效果更佳: https://www.bilibili.com/video/BV1NE411Q7Nx/?spm_id_from=333.1007.top_right_bar_window_custom_collection.content.click&vd_source ...
https://www.bilibili.com/video/BV1NE411Q7Nx/?spm_id_from=333.1007.top_right_bar_window_custom_collection.content.click&vd_source=4c3c519d33c113799489c7417a0a4c0e
環境說明:
-
jdk 8 +
-
MySQL 5.7.19
-
maven-3.6.1
-
IDEA
學習前需要掌握:
-
JDBC
-
MySQL
-
Java 基礎
-
Maven
-
1.1、什麼是MyBatis
-
MyBatis 是一款優秀的持久層框架
-
MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集的過程
-
MyBatis 可以使用簡單的 XML 或註解來配置和映射原生信息,將介面和 Java 的 實體類 【Plain Old Java Objects,普通的 Java對象】映射成資料庫中的記錄。
-
MyBatis 本是apache的一個開源項目ibatis, 2010年這個項目由apache 遷移到了google code,並且改名為MyBatis 。
-
2013年11月遷移到Github
-
Maven倉庫
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
-
Mybatis官方文檔 : https://mybatis.org/mybatis-3/https://mybatis.org/mybatis-3/
-
GitHub : https://github.com/mybatis/mybatis-3
1.2、持久化
持久化是將程式數據在持久狀態和瞬時狀態間轉換的機制。
-
即把數據(如記憶體中的對象)保存到可永久保存的存儲設備中(如磁碟)。持久化的主要應用是將記憶體中的對象存儲在資料庫中,或者存儲在磁碟文件中、XML數據文件中等等。
-
JDBC就是一種持久化機制。文件IO也是一種持久化機制。
-
在生活中 : 將鮮肉冷藏,吃的時候再解凍的方法也是。將水果做成罐頭的方法也是。
為什麼需要持久化服務呢?那是由於記憶體本身的缺陷引起的
-
記憶體斷電後數據會丟失,但有一些對象是無論如何都不能丟失的,比如銀行賬號等,遺憾的是,人們還無法保證記憶體永不掉電。
-
記憶體過於昂貴,與硬碟、光碟等外存相比,記憶體的價格要高2~3個數量級,而且維持成本也高,至少需要一直供電吧。所以即使對象不需要永久保存,也會因為記憶體的容量限制不能一直呆在記憶體中,需要持久化來緩存到外存。
1.3、持久層
什麼是持久層?
-
完成持久化工作的代碼塊 . ----> dao層 【DAO (Data Access Object) 數據訪問對象】
-
大多數情況下特別是企業級應用,數據持久化往往也就意味著將記憶體中的數據保存到磁碟上加以固化,而持久化的實現過程則大多通過各種關係資料庫來完成。
-
不過這裡有一個字需要特別強調,也就是所謂的“層”。對於應用系統而言,數據持久功能大多是必不可少的組成部分。也就是說,我們的系統中,已經天然的具備了“持久層”概念?也許是,但也許實際情況並非如此。之所以要獨立出一個“持久層”的概念,而不是“持久模塊”,“持久單元”,也就意味著,我們的系統架構中,應該有一個相對獨立的邏輯層面,專註於數據持久化邏輯的實現.
-
與系統其他部分相對而言,這個層面應該具有一個較為清晰和嚴格的邏輯邊界。【說白了就是用來操作資料庫存在的!】
1.4、為什麼需要Mybatis
-
Mybatis就是幫助程式猿將數據存入資料庫中 , 和從資料庫中取數據 .
-
傳統的jdbc操作 , 有很多重覆代碼塊 .比如 : 數據取出時的封裝 , 資料庫的建立連接等等... , 通過框架可以減少重覆代碼,提高開發效率 .
-
MyBatis 是一個半自動化的ORM框架 (Object Relationship Mapping) -->對象關係映射
-
所有的事情,不用Mybatis依舊可以做到,只是用了它,所有實現會更加簡單!技術沒有高低之分,只有使用這個技術的人有高低之別
-
MyBatis的優點
-
-
簡單易學:本身就很小且簡單。沒有任何第三方依賴,最簡單安裝只要兩個jar文件+配置幾個sql映射文件就可以了,易於學習,易於使用,通過文檔和源代碼,可以比較完全的掌握它的設計思路和實現。
-
靈活:mybatis不會對應用程式或者資料庫的現有設計強加任何影響。sql寫在xml里,便於統一管理和優化。通過sql語句可以滿足操作資料庫的所有需求。
-
解除sql與程式代碼的耦合:通過提供DAO層,將業務邏輯和數據訪問邏輯分離,使系統的設計更清晰,更易維護,更易單元測試。sql和代碼的分離,提高了可維護性。
-
提供xml標簽,支持編寫動態sql。
-
.......
-
-
最重要的一點,使用的人多!公司需要!
2、第一個Mybatis程式
思路流程:搭建環境-->導入Mybatis--->編寫代碼--->測試
代碼演示
-
1、搭建實驗資料庫
CREATE DATABASE `mybatis`;
USE `mybatis`;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(20) NOT NULL,
`name` varchar(30) DEFAULT NULL,
`pwd` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `user`(`id`,`name`,`pwd`) values (1,'英傑','123456'),(2,'張三','abcdef'),(3,'李四','987654');
-
2、導入MyBatis相關 jar 包
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
-
3、編寫MyBatis核心配置文件
-
查看幫助文檔
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://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?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="417020"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration> -
-
4、編寫MyBatis工具類
-
查看幫助文檔
package com.cherriesovo.utils;
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 java.io.IOException;
import java.io.InputStream;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//第一步:獲取sqlSessionFactory對象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//從sqlSessionFactory中獲取SqlSession實例
public static SqlSession getSession(){
return sqlSessionFactory.openSession();
}
} -
-
5、創建實體類
package com.cherriesovo.pojo;
public class User {
private int id; //id
private String name; //姓名
private String pwd; //密碼
public User() {
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
-
6、編寫Mapper介面類
package com.cherriesovo.dao;
import com.cherriesovo.pojo.User;
import java.util.List;
public interface UserMapper {
List<User> selectUser();
}
-
7、編寫Mapper.xml配置文件
namespace 十分重要,不能寫錯,一個namespace綁定一個Dao/Mapper介面!
<?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.cherriesovo.dao.UserMapper">
<select id="selectUser" resultType="com.cherriesovo.pojo.User">
select * from user
</select>
</mapper>
-
8、編寫測試類
-
Junit 包測試
-
public class UserDaoTest {
@Test
public void SelectUser(){
//從工具類中獲取SQLSession
SqlSession session = MybatisUtils.getSession();
//從SQLSession獲取mapper
UserMapper mapper = session.getMapper(UserMapper.class);
//執行查詢
List<User> users = mapper.selectUser();
for (User user : users) {
System.out.println(user);
}
//關閉連接
session.close();
}
}
-
9、運行測試,成功的查詢出來的我們的數據,ok!
可能出現的問題:Maven靜態資源過濾問題
解決方案:在pom.xml中添加:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
整體思路:
-
先進性準備工作:MybatisUtils工具類、Mybatis-config.xml配置文件
-
編寫實體類,介面,然後編寫Mapper.xml配置文件(namespace綁定介面,裡面的標簽綁定方法,resultType是返回值類型)
-
編寫測試類
3、CRUD
3.1、需求:根據id查詢用戶
-
在UserMapper中添加對應方法
public interface UserMapper {
//查詢指定id的用戶
User selectUserbyID(int id);
}
-
在UserMapper.xml中添加Select語句
<?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">
<!--namespace與介面建立聯繫-->
<!--id="selectUser"相當於去重寫了介面UserMapper中的selectUser()-->
<!--resultType是sql語句執行的返回值-->
<mapper namespace="com.cherriesovo.dao.UserMapper">
<!--查詢指定id的用戶-->
<select id="selectUserbyID" resultType="com.cherriesovo.pojo.User">
select * from user where id = #{id}
</select>
</mapper>
-
測試類中測試
@Test
public void selectUserbyID(){
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUserbyID(1);
System.out.println(user);
session.close();
}
3.2、需求:給資料庫增加一個用戶
-
UserMapper中添加對應方法
public interface UserMapper {
//插入用戶
int addUser(User user);
}
-
在UserMapper.xml中添加insert語句
<?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">
<!--namespace與介面建立聯繫-->
<!--id="selectUser"相當於去重寫了介面UserMapper中的selectUser()-->
<!--resultType是sql語句執行的返回值-->
<mapper namespace="com.cherriesovo.dao.UserMapper">
<!--插入用戶-->
<insert id="addUser" parameterType="com.cherriesovo.pojo.User">
insert into user(id,name,pwd) values (#{id},#{name},#{pwd})
</insert>
</mapper>
-
測試類中測試
註意:增刪改必須提交事務,否則無法成功
@Test
public void addUser(){
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
int i = mapper.addUser(new User(4,"小貓","123456"));
//註意:增加、刪除、修改必須提交事務
session.commit(); //提交事務
session.close();
}
3.3、需求:修改用戶的信息
-
UserMapper中添加對應方法
public interface UserMapper {
//修改用戶
int updateUser(User user);
}
-
在UserMapper.xml中添加update語句
<?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">
<!--namespace與介面建立聯繫-->
<!--id="selectUser"相當於去重寫了介面UserMapper中的selectUser()-->
<!--resultType是sql語句執行的返回值-->
<mapper namespace="com.cherriesovo.dao.UserMapper">
<!--修改用戶-->
<update id="updateUser" parameterType="com.cherriesovo.pojo.User">
update user set name = #{name},pwd = #{pwd} where id = #{id}
</update>
</mapper>
-
測試類中測試
@Test
public void updateUser(){
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
int i = mapper.updateUser(new User(4,"二狗子","666666"));
//註意:增加、刪除、修改必須提交事務
session.commit(); //提交事務
session.close();
}
3.4、需求:根據id刪除一個用戶
-
UserMapper中添加對應方法
public interface UserMapper {
//刪除用戶
int deleteUser(int id);
}
-
在UserMapper.xml中添加delete語句
<?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">
<!--namespace與介面建立聯繫-->
<!--id="selectUser"相當於去重寫了介面UserMapper中的selectUser()-->
<!--resultType是sql語句執行的返回值-->
<mapper namespace="com.cherriesovo.dao.UserMapper">
<!--刪除用戶-->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
</mapper>
-
測試類中測試
@Test
public void deleteUser(){
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
mapper.deleteUser(4);
//註意:增加、刪除、修改必須提交事務
session.commit(); //提交事務
session.close();
}
註意:只有查詢需要resultType,增刪改不需要,其中parameterType為int型的可以省略。
小結:
-
所有的增刪改操作都需要提交事務!
-
介面所有的普通參數,儘量都寫上@Param參數,尤其是多個參數時,必須寫上!
-
有時候根據業務的需求,可以考慮使用map傳遞參數!
-
為了規範操作,在SQL的配置文件中,我們儘量將Parameter參數和resultType都寫上!
3.5、萬能的Map
使用Map的好處:不需要知道資料庫裡面有什麼,只需要去查對應的欄位。假如我們的實體類或者數據表中的欄位過多,我們應該考慮使用map。
使用Map的方式修改用戶信息
-
UserMapper中添加對應方法
public interface UserMapper {
//修改用戶(使用map實現)
int updateUserbyMap(Map<String,Object> map);
}
-
在UserMapper.xml中添加delete語句
<?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">
<!--namespace與介面建立聯繫-->
<!--id="selectUser"相當於去重寫了介面UserMapper中的selectUser()-->
<!--resultType是sql語句執行的返回值-->
<mapper namespace="com.cherriesovo.dao.UserMapper">
<!--修改用戶by Map-->
<update id="updateUserbyMap" parameterType="map">
update user set pwd = #{password} where id = #{userid}
</update>
</mapper>
-
測試類中測試
@Test
public void updateUserbyMap(){
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("password","55555");
map.put("userid",2);
mapper.updateUserbyMap(map);
//註意:增加、刪除、修改必須提交事務
session.commit(); //提交事務
session.close();
}
Map和對象的使用區別:
-
new一個對象需要知道所有的欄位,而Map只需要知道所用的欄位即可;
-
對象使用時配置文件中欄位名必須和資料庫一一對應,而Map可以任意;
<!--修改用戶by Map-->
<update id="updateUserbyMap" parameterType="map">
update user set pwd = #{password} where id = #{userid}
</update>
<!--修改用戶-->
<update id="updateUser" parameterType="com.cherriesovo.pojo.User">
update user set name = #{name},pwd = #{pwd} where id = #{id}
</update>
3.6、模糊查詢
方式一:在Java代碼中添加sql通配符%%。
<!--查詢所有姓李的用戶-->
<select id="selectUserbyLike" resultType="com.cherriesovo.pojo.User">
select * from user where name like #{value}
</select>
//3、執行查詢
List<User> users = mapper.selectUserbyLike("%李%");
方式二:在sql語句中拼接通配符,會引起sql註入
<!--查詢所有姓李的用戶-->
<select id="selectUserbyLike" resultType="com.cherriesovo.pojo.User">
select * from user where name like "%"#{value}"%"
</select>
//3、執行查詢
List<User> users = mapper.selectUserbyLike("李");
4、配置解析
4.1、核心配置文件
-
mybatis-config.xml 系統核心配置文件
-
MyBatis 的配置文件包含了會深深影響 MyBatis 行為的設置和屬性信息。
-
能配置的內容如下:
configuration(配置)
properties(屬性)
settings(設置)
typeAliases(類型別名)
typeHandlers(類型處理器)
objectFactory(對象工廠)
plugins(插件)
environments(環境配置)
environment(環境變數)
transactionManager(事務管理器)
dataSource(數據源)
databaseIdProvider(資料庫廠商標識)
mappers(映射器)
<!-- 註意元素節點的順序!順序不對會報錯 -->
4.2、environments元素
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
-
配置MyBatis的多套運行環境,將SQL映射到多個不同的資料庫上,必須指定其中一個為預設運行環境(通過default指定)
-
子元素節點:environment
-
-
dataSource 元素使用標準的 JDBC 數據源介面來配置 JDBC 連接對象的資源。
-
數據源是必須配置的。
-
有三種內建的數據源類型
type="[UNPOOLED|POOLED|JNDI]")
-
unpooled:這個數據源的實現只是每次被請求時打開和關閉連接。
-
pooled:這種數據源的實現利用“池”的概念將 JDBC 連接對象組織起來 , 這是一種使得併發 Web 應用快速響應請求的流行處理方式。
-
jndi:這個數據源的實現是為了能在如 Spring 或應用伺服器這類容器中使用,容器可以集中或在外部配置數據源,然後放置一個 JNDI 上下文的引用。
-
數據源也有很多第三方的實現,比如dbcp,c3p0,druid等等....
-
詳情:點擊查看官方文檔
-
這兩種事務管理器類型都不需要設置任何屬性。
-
具體的一套環境,通過設置id進行區別,id保證唯一!
-
子元素節點:transactionManager - [ 事務管理器 ]
<!-- 語法 -->
<transactionManager type="[ JDBC | MANAGED ]"/> -
子元素節點:數據源(dataSource)
-
4.3、映射器(mappers)
mappers
-
映射器 : 定義映射SQL語句文件
-
既然 MyBatis 的行為其他元素已經配置完了,我們現在就要定義 SQL 映射語句了。但是首先我們需要告訴 MyBatis 到哪裡去找到這些語句。Java 在自動查找這方面沒有提供一個很好的方法,所以最佳的方式是告訴 MyBatis 到哪裡去找映射文件。你可以使用相對於類路徑的資源引用, 或完全限定資源定位符(包括
file:///
的 URL),或類名和包名等。映射器是MyBatis中最核心的組件之一,在MyBatis 3之前,只支持xml映射器,即:所有的SQL語句都必須在xml文件中配置。而從MyBatis 3開始,還支持介面映射器,這種映射器方式允許以Java代碼的方式註解定義SQL語句,非常簡潔。
引入資源方式
<!-- 方式一:使用相對於類路徑的資源引用(推薦使用) -->
<mappers>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 方式二:使用完全限定資源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
</mappers>
<!--方式三:
使用映射器介面實現類的完全限定類名
需要配置文件名稱和介面名稱一致,並且位於同一目錄下
-->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
</mappers>
<!--方式四:
將包內的映射器介面實現全部註冊為映射器
但是需要配置文件名稱和介面名稱一致,並且位於同一目錄下
-->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
Mapper文件
<?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.kuang.mapper.UserMapper">
</mapper>
-
namespace中文意思:命名空間,作用如下:
-
-
namespace的命名必須跟某個介面同名
-
介面中的方法與映射文件中sql語句id應該一一對應
-
-
namespace和子元素的id聯合保證唯一, 區別不同的mapper
-
綁定DAO介面
-
namespace命名規則 : 包名+類名
-
MyBatis 的真正強大在於它的映射語句,這是它的魔力所在。由於它的異常強大,映射器的 XML 文件就顯得相對簡單。如果拿它跟具有相同功能的 JDBC 代碼進行對比,你會立即發現省掉了將近 95% 的代碼。MyBatis 為聚焦於 SQL 而構建,以儘可能地為你減少麻煩。
4.4、屬性(Properties)(重要)
資料庫這些屬性都是可外部配置且可動態替換的,既可以在典型的 Java 屬性文件中配置,亦可通過 properties 元素的子元素來傳遞,其中Java 屬性文件的優先順序更高。
我們來優化我們的配置文件:
第一步 :在資源目錄下新建一個db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8
username=root
password=417020
第二步 : 將文件導入properties 配置文件(需要放置在<configuration>標簽中的最上方)
<!--導入properties文件-->
<properties resource="db.properties"/>
4.5、typeAliases別名(重要)
類型別名是為 Java 類型設置一個短的名字。它只和 XML 配置有關,存在的意義僅在於用來減少類完全限定名的冗餘。
<!--方式一-->
<!--配置別名,註意順序-->
<typeAliases>
<typeAlias type="com.cherriesovo.pojo.User" alias="User"/>
</typeAliases>
當這樣配置時,User
可以用在任何使用com.kuang.pojo.User
的地方。
也可以指定一個包名,MyBatis 會在包名下麵搜索需要的 Java Bean,比如:
<!--方式二-->
<typeAliases>
<package name="com.cherriesovo.pojo"/>
</typeAliases>
每一個在包 com.kuang.pojo
中的 Java Bean(類),在沒有註解的情況下,會使用 Bean(類) 的首字母小寫的非限定類名來作為它的別名。
例如:User的別名就是user
若有註解,則別名為其註解值。見下麵的例子:
//方式三
@Alias("user")
public class User {
...
}
去官網查看一下Mybatis預設的一些類型別名!
4.6、設置(sittings)(重要)
-
設置(settings)相關 => 查看幫助文檔
-
-
懶載入
-
日誌實現
-
緩存開啟關閉
-
-
一個配置完整的 settings 元素的示例如下:
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
類型處理器
-
無論是 MyBatis 在預處理語句(PreparedStatement)中設置一個參數時,還是從結果集中取出一個值時, 都會用類型處理器將獲取的值以合適的方式轉換成 Java 類型。
-
你可以重寫類型處理器或創建你自己的類型處理器來處理不支持的或非標準的類型。【瞭解即可】
對象工廠
-
MyBatis 每次創建結果對象的新實例時,它都會使用一個對象工廠(ObjectFactory)實例來完成。
-
預設的對象工廠需要做的僅僅是實例化目標類,要麼通過預設構造方法,要麼在參數映射存在的時候通過有參構造方法來實例化。
-
如果想覆蓋對象工廠的預設行為,則可以通過創建自己的對象工廠來實現。【瞭解即可】
4.7、作用域(Scope)和生命周期
我們目前已經討論過的不同作用域和生命周期類是至關重要的,因為錯誤的使用會導致非常嚴重的併發問題。
程式開始執行後,SqlSessionFactoryBuilder 讀取配置文件來生產SqlSessionFactory;SqlSessionFactory 生產SqlSession,SqlSession獲取SqlMapper,每一個SqlMapper都對應著一個具體的業務。
作用域理解
-
SqlSessionFactoryBuilder 的作用在於創建 SqlSessionFactory,創建成功後,SqlSessionFactoryBuilder 就失去了作用,所以它只能存在於創建 SqlSessionFactory 的方法中,而不要讓其長期存在。因此 SqlSessionFactoryBuilder 實例的最佳作用域是方法作用域(也就是局部方法變數)。
-
SqlSessionFactory 可以被認為是一個資料庫連接池,它的作用是創建 SqlSession 介面對象。因為 MyBatis 的本質就是 Java 對資料庫的操作,所以 SqlSessionFactory 的生命周期存在於整個 MyBatis 的應用之中,所以一旦創建了 SqlSessionFactory,就要長期保存它,直至不再使用 MyBatis 應用,所以可以認為 SqlSessionFactory 的生命周期就等同於 MyBatis 的應用周期。
-
由於 SqlSessionFactory 是一個對資料庫的連接池,所以它占據著資料庫的連接資源。如果創建多個 SqlSessionFactory,那麼就存在多個資料庫連接池,這樣不利於對資料庫資源的控制,也會導致資料庫連接資源被消耗光,出現系統宕機等情況,所以儘量避免發生這樣的情況。
-
因此在一般的應用中我們往往希望 SqlSessionFactory 作為一個單例(只存在一個),讓它在應用中被共用。所以說 SqlSessionFactory 的最佳作用域是應用作用域,就是說應用開始他就開始,應用結束他才結束。
-
如果說 SqlSessionFactory 相當於資料庫連接池,那麼 SqlSession 就相當於一個資料庫連接(Connection 對象),你可以在一個事務裡面執行多條 SQL,然後通過它的 commit、rollback 等方法,提交或者回滾事務。所以它應該存活在一個業務請求中,處理完整個請求後,應該關閉這條連接,讓它歸還給 SqlSessionFactory,否則資料庫資源就很快被耗費精光,系統就會癱瘓,所以用 try...catch...finally... 語句來保證其正確關閉。
-
所以 SqlSession 的最佳的作用域是請求或方法作用域。
學會了Crud,和基本的配置及原理,後面就可以學習些業務開發。。。
5、ResultMap
作用:解決實體類屬性名和資料庫欄位名不一致的問題
環境:新建一個項目,將之前的項目拷貝過來
1、查看之前的資料庫的欄位名
2、Java中的實體類設計
public class User {
private int id; //id
private String name; //姓名
private String password; //密碼和資料庫名不一樣!
//構造
//set/get
//toString()
}
3、介面
public interface UserMapper {
//查詢指定id的用戶
User selectUserbyID(int id);
}
4、mapper映射文件
<select id="selectUserbyId" resultType="User">
select * from user where id = #{id}
</select>
5、測試
@Test
public void selectUserbyID(){
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUserbyID(3);
System.out.println(user);
session.close();
}
結果:
-
User{id=1, name='英傑', password='null'}
-
查詢出來發現 password 為空 . 說明出現了問題!
分析:
-
select * from user where id = #{id} 可以看做
select id,name,pwd from user where id = #{id}
-
mybatis會根據這些查詢的列名(會將列名轉化為小寫,資料庫不區分大小寫) , 去對應的實體類中查找相應列名的set方法設值 , 由於找不到setPwd() , 所以password返回null ; 【自動映射】
解決方案
方案一:為列名指定別名 , 別名和java實體類的屬性名一致;
<select id="selectUserbyId" resultType="User">
select id , name , pwd as password from user where id = #{id}
</select>
方案二:使用結果集映射->ResultMap 【推薦】
<!--結果集映射-->
<resultMap id="SelectUser" type="User">
<!--column是資料庫中的欄位;property是實體類中的屬性,將二者對應起來-->
<result column="pwd" property="password"/>
</resultMap>
<!--查詢指定id的用戶-->
<select id="selectUserbyID" parameterType="int" resultMap="SelectUser">
select * from user where id = #{id}
</select>
ResultMap
自動映射
-
resultMap
元素是 MyBatis 中最重要最強大的元素。它可以讓你從 90% 的 JDBCResultSets
數據提取代碼中解放出來。 -
實際上,在為一些比如連接的複雜語句編寫映射代碼的時候,一份
resultMap
能夠代替實現同等功能的長達數千行的代碼。 -
ResultMap 的設計思想是,對於簡單的語句根本不需要配置顯式的結果映射,而對於複雜一點的語句只需要描述它們的關係就行了。
6、日誌
6.1、日誌工廠
思考:我們在測試SQL的時候,要是能夠在控制台輸出 SQL 的話,是不是就能夠有更快的排錯效率?
如果一個 資料庫相關的操作出現了問題,我們可以根據輸出的SQL語句快速排查問題。
對於以往的開發過程,我們會經常使用到debug模式來調節,跟蹤我們的代碼執行過程。但是現在使用Mybatis是基於介面,配置文件的源代碼執行過程。因此,我們必須選擇日誌工具來作為我們開發,調節程式的工具。
Mybatis內置的日誌工廠提供日誌功能,具體的日誌實現有以下幾種工具:
-
SLF4J
-
Apache Commons Logging
-
Log4j 2
-
Log4j
-
JDK logging
具體選擇哪個日誌實現工具由MyBatis的內置日誌工廠確定。它會使用最先找到的(按上文列舉的順序查找)。如果一個都未找到,日誌功能就會被禁用。
6.2、標準日誌實現
指定 MyBatis 應該使用哪個日誌記錄實現。如果此設置不存在,則會自動發現日誌記錄實現。
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
測試,可以看到控制台有大量的輸出!我們可以通過這些輸出來判斷程式到底哪裡出了Bug。
6.3、log4J
簡介:
-
Log4j是Apache的一個開源項目
-
通過使用Log4j,我們可以控制日誌信息輸送的目的地:控制台,文本,GUI組件....
-
我們也可以控制每一條日誌的輸出格式;
-
通過定義每一條日誌信息的級別,我們能夠更加細緻地控制日誌的生成過程。最令人感興趣的就是,這些可以通過一個配置文件來靈活地進行配置,而不需要修改應用的代碼。
使用步驟:
1、導入log4j的包
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2、配置文件編寫
#將等級為DEBUG的日誌信息輸出到console和file這兩個目的地,console和file的定義在下麵的代碼
log4j.rootLogger=DEBUG,console,file
#控制台輸出的相關設置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件輸出的相關設置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/cherriesovo.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日誌輸出級別
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
3、setting設置日誌實現
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
4、在程式中使用Log4j進行輸出!
//註意導包:org.apache.log4j.Logger
static Logger logger = Logger.getLogger(UserDaoTest.class);
@Test
public void selectUserbyID(){
logger.info("info:進入selectUser方法");
logger.debug("debug:進入selectUser方法");
logger.error("err