環(huán)境:
JDK1.8噪矛,Mysql5.7医清,maven3.6.1起暮,IDEA
回顧:
JDBC,Mysql会烙,java基礎(chǔ)负懦,Maven,junit
SSM框架:
配置文件:最好的方式:看官網(wǎng)文檔:https://mybatis.org/mybatis-3/
1.簡(jiǎn)介:
1.1 什么是Mybatis
- MyBatis 是一款優(yōu)秀的持久層框架柏腻。
- 它支持自定義 SQL纸厉、存儲(chǔ)過程以及高級(jí)映射。
- MyBatis 免除了幾乎所有的 JDBC 代碼以及設(shè)置參數(shù)和獲取結(jié)果集的工作五嫂。
- MyBatis 可以通過簡(jiǎn)單的 XML 或注解來配置和映射原始類型颗品、接口和 Java POJO(Plain Old Java Objects肯尺,普通老式 Java 對(duì)象)為數(shù)據(jù)庫(kù)中的記錄。
- MyBatis本是apache的一個(gè)開源項(xiàng)目iBatis躯枢,2010年這個(gè)項(xiàng)目由apache software foundation遷移到了google code则吟,并且改名為MyBatis。2013年11月遷移到Github锄蹂。
獲取Mybatis:
- maven倉(cāng)庫(kù):
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
- gitee:https://gitee.com/geng_zhao_kai/mybatis-3?_from=gitee_search
- 中文文檔:https://mybatis.org/mybatis-3/zh/index.html
1.2 持久化
數(shù)據(jù)持久化
- 持久化就是將程序的數(shù)據(jù)在持久狀態(tài)和瞬時(shí)狀態(tài)轉(zhuǎn)化的過程氓仲。
- 內(nèi)存:斷電即失
- 數(shù)據(jù)庫(kù)(jdbc),io文件持久化
為什么需要持久化得糜?
- 有一些對(duì)象敬扛,不能讓他丟掉。
- 內(nèi)存太貴
1.3 持久層
- 完成持久化工作的代碼塊
- 層界限十分明顯掀亩。
1.4 為什么需要Mybatis舔哪?
- 幫助程序員把數(shù)據(jù)存入到數(shù)據(jù)庫(kù)中
- 傳統(tǒng)JDBC代碼太復(fù)雜了欢顷,簡(jiǎn)化槽棍、框架、自動(dòng)化
- ...
2.第一個(gè)Mybatis程序
思路:搭建環(huán)境--導(dǎo)入Mybatis--編寫代碼--測(cè)試
2.1 搭建環(huán)境
數(shù)據(jù)庫(kù):
CREATE DATABASE `mybatis`;
USE `mybatis`;
CREATE TABLE `user`(
`id` INT(20) NOT NULL PRIMARY KEY,
`name` VARCHAR(30) DEFAULT NULL,
`pwd` VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user`(`id`,`name`,`pwd`)VALUES
(1,'張三','123456'),
(2,'李四','123456'),
(3,'王五','123456')
新建項(xiàng)目:
1.普通maven項(xiàng)目
2.刪除src目錄
3.導(dǎo)入maven依賴
<!-- 導(dǎo)入依賴 -->
<dependencies>
<!-- mysql驅(qū)動(dòng) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
2.1 創(chuàng)建一個(gè)模塊
編寫mybatis的核心配置文件
編寫mybatis的工具類
在resources下配置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.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&characterEncoding=UTF-8&useUnicode=true&serverTimezone=GMT""/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
</configuration>
從 XML 中構(gòu)建 SqlSessionFactory抬驴,從 SqlSessionFactory 中獲取 SqlSession
在util下配置com.qwe.util.MybatisUtils
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;
//SqlSessionFactory -->sqlSession
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//使用Mybatis第一步:獲取sqlSessionFactory對(duì)象
//這里出錯(cuò)后面會(huì)空指針異常
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//既然有了 SqlSessionFactory炼七,顧名思義,我們可以從中獲得 SqlSession 的實(shí)例布持。
// SqlSession 提供了在數(shù)據(jù)庫(kù)執(zhí)行 SQL 命令所需的所有方法豌拙。你可以通過 SqlSession 實(shí)例來直接執(zhí)行已映射的 SQL 語(yǔ)句。
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
}
2.3 編寫代碼
- 實(shí)體類
- Dao接口
- 接口實(shí)現(xiàn)類
探究已映射的 SQL 語(yǔ)句
一個(gè)語(yǔ)句既可以通過 XML 定義题暖,也可以通過注解定義按傅。事實(shí)上 MyBatis 提供的所有特性都可以利用基于 XML 的映射語(yǔ)言來實(shí)現(xiàn),這使得 MyBatis 在過去的數(shù)年間得以流行胧卤。這里給出一個(gè)基于 XML 映射語(yǔ)句的示例唯绍,它應(yīng)該可以滿足上個(gè)示例中 SqlSession 的調(diào)用。
<?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="org.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>
- 實(shí)體類 com.qwe.pojo.User
public class User {
private int 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 + '\'' +
'}'; }
}
- Dao接口 com.qwe.dao.UserDao
import com.qwe.pojo.User;
import java.util.List;
public interface UserDao {
//獲取UserList
List<User> getUserList();
}
- 接口實(shí)現(xiàn)類 由原來的UserDaoImpl轉(zhuǎn)變?yōu)橐粋€(gè)Mapper配置文件 UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace綁定一個(gè)對(duì)應(yīng)的Dao/Mapper接口 -->
<mapper namespace="com.qwe.dao.UserDao">//必須指定命名空間
<!-- 查詢語(yǔ)句 id原來的方法名字 type類型 map集合-->
<select id="getUserList" resultType="com.qwe.pojo.User">
select * from mybatis.user
</select>
</mapper>
2.4 測(cè)試
注意點(diǎn):
1 org.apache.ibatis.binding.BindingException:Type interface com.*.dao.UserDao is not known to the MapperRegistry
解決方法:mybatis-config.xml
<!-- 每一個(gè)Mapper.xml文件都需要在Mybatis核心配置文件中注冊(cè)枝誊! -->
<mappers>
<mapper resource="com/qwe/dao/UserMapper.xml"/>
</mappers>
2 java.io.IOException: Could not find resource org/mybatis/example/mybatis-config.xml
解決辦法:maven中約定大于配置 在父項(xiàng)目和子項(xiàng)目pom.xml文件加入
<!--在build中配置resources况芒,來防止我們資源導(dǎo)出失敗的問題-->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
- junit測(cè)試
public class UserDaoTest {
@Test
public void test(){
//第一步:獲取SqlSession對(duì)象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//執(zhí)行SQL
//方式一:getMapper
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userList = userDao.getUserList();
//方式二:以前的方法
// List<User> userList = sqlSession.selectList("com.qwe.dao.UserDao.getUserList");
for (User user:userList){
System.out.println(user);
}
//關(guān)閉SqlSession
sqlSession.close();
}
}
步驟:
1 在pom.xml中導(dǎo)入mysql和mybatis的jar包
2 需要一個(gè)sqlSesionFactory對(duì)象創(chuàng)建了mybatis-config.xml
3 建造工具類MybatisUtils
4 實(shí)體類里接口UserDao,UserMapper.xml代替實(shí)現(xiàn)類
作用域(Scope)
SqlSessionFactoryBuilder
這個(gè)類可以被實(shí)例化叶撒、使用和丟棄绝骚,一旦創(chuàng)建了 SqlSessionFactory,就不再需要它了祠够。
SqlSessionFactory
SqlSessionFactory 一旦被創(chuàng)建就應(yīng)該在應(yīng)用的運(yùn)行期間一直存在压汪。 最簡(jiǎn)單的就是使用單例模式或者靜態(tài)單例模式。
SqlSession
SqlSession 的實(shí)例不是線程安全的古瓤,因此是不能被共享的止剖,所以它的最佳的作用域是請(qǐng)求或方法作用域。 換句話說,每次收到 HTTP 請(qǐng)求滴须,就可以打開一個(gè) SqlSession舌狗,返回一個(gè)響應(yīng)后,就關(guān)閉它扔水。 一個(gè)確保 SqlSession 關(guān)閉的標(biāo)準(zhǔn)模式:
try (SqlSession session = sqlSessionFactory.openSession()) {
// 你的應(yīng)用邏輯代碼
}
3.增刪改(必須要提交事務(wù))
1.namespace
namespace中的包名要和接口Dao/Mapper的包名一致
2.select
選擇痛侍,查詢語(yǔ)句
- id:就是對(duì)應(yīng)的namespace中的方法名
- resultType:sql語(yǔ)句執(zhí)行的返回值
- parameterType:參數(shù)類型
3.Insert
1 編寫接口 UserMapper
//增加用戶
int addUser(User user);
2 編寫對(duì)應(yīng)的mapper中的sql語(yǔ)句 UserMapper.xml
<insert id="addUser" parameterType="com.qwe.pojo.User" >
insert into mybatis.user (id,name,pwd) values(#{id},#{name},#{pwd});
</insert>
3 測(cè)試 UserMapperTest
@Test
public void addUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int res = mapper.addUser(new User(4, "哈哈", "123456"));
if (res>0){
System.out.println("插入成功");
}
//提交事務(wù)
sqlSession.commit();
sqlSession.close();
}
4.Update
1 編寫接口
//修改用戶
int updateUser(User user);
2 編寫對(duì)應(yīng)的mapper中的sql語(yǔ)句
<update id="updateUser" parameterType="com.qwe.pojo.User">
update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id};
</update>
3 測(cè)試
@Test
public void updateUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.updateUser(new User(4,"趙四","123456"));
sqlSession.commit();
sqlSession.close();
}
5.Delete
1 編寫接口
//刪除用戶
int deleteUser(int id);
2 編寫對(duì)應(yīng)的mapper中的sql語(yǔ)句
<delete id="deleteUser" parameterType="int">
delete from mybatis.user where id =#{id};
</delete>
3 測(cè)試
@Test
public void deleteUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.deleteUser(4);
sqlSession.commit();
sqlSession.close();
}
6.萬能的Map
假設(shè)實(shí)體類或數(shù)據(jù)庫(kù)中的表、字段或者參數(shù)過多魔市,應(yīng)當(dāng)考慮Map
//萬能的map
int addUser2(Map<String,Object> map);
<insert id="addUser2" parameterType="map">
insert into mybatis.user(id,pwd) values(#{userid},#{password});
</insert>
@Test
public void addUser2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String,Object> map = new HashMap<String, Object>();
map.put("userid",4);
map.put("password","123456");
mapper.addUser2(map);
sqlSession.close();
}
Map傳遞參數(shù)主届,直接在sql中取出key即可 parameterType="map"
對(duì)象傳遞參數(shù),直接在sql中取對(duì)象的屬性即可 parameterType="Object"
只有一個(gè)基本類型參數(shù)的情況下待德,可以直接在sql中取到
多個(gè)參數(shù)用Map或者注解
7.模糊查詢
List<User> getUserLike(String value);
<select id="getUserLike" resultType="com.qwe.pojo.User">
select * from mybatis.user where name like "%"#{value }"%"
</select>
@Test
public void getUserLike(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserLike("王");
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
1 java代碼執(zhí)行的時(shí)候君丁,傳遞通配符% %
List<User> userList = mapper.getUserLike("%王%");
2 在sql拼接中使用通配符
select * from mybatis.user where name like "%"#{value }"%"
4.配置解析
4.1 核心文件配置
- mybatis-config.xml
- MyBatis的配置文件包括了慧深深影響MyBatis行為的設(shè)置和屬性信息。
配置文檔的頂層結(jié)構(gòu)如下:
configuration(配置)
- properties(屬性)
- settings(設(shè)置)
- typeAliases(類型別名)
- typeHandlers(類型處理器)
- objectFactory(對(duì)象工廠)
- plugins(插件)
- environments(環(huán)境配置)
* environment(環(huán)境變量)
* transactionManager(事務(wù)管理器)
* dataSource(數(shù)據(jù)源) - databaseIdProvider(數(shù)據(jù)庫(kù)廠商標(biāo)識(shí))
- mappers(映射器)
4.2環(huán)境配置(environments)
MyBatis 可以配置成適應(yīng)多種環(huán)境
不過要記捉堋:盡管可以配置多個(gè)環(huán)境绘闷,但每個(gè) SqlSessionFactory 實(shí)例只能選擇一種環(huán)境。
environments 元素定義了如何配置環(huán)境较坛。
<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>
注意一些關(guān)鍵點(diǎn):
1 默認(rèn)使用的環(huán)境 ID(比如:default="development")印蔗。
2 每個(gè) environment 元素定義的環(huán)境 ID(比如:id="development")。
3 事務(wù)管理器的配置(比如:type="JDBC")丑勤。
4 數(shù)據(jù)源的配置(比如:type="POOLED")华嘹。
默認(rèn)環(huán)境和環(huán)境 ID 顧名思義。 環(huán)境可以隨意命名法竞,但務(wù)必保證默認(rèn)的環(huán)境 ID 要匹配其中一個(gè)環(huán)境 ID耙厚。
事務(wù)管理器(transactionManager)
在 MyBatis 中有兩種類型的事務(wù)管理器(也就是 type="[JDBC|MANAGED]"):
- JDBC – 這個(gè)配置直接使用了 JDBC 的提交和回滾設(shè)施,它依賴從數(shù)據(jù)源獲得的連接來管理事務(wù)作用域岔霸。 (默認(rèn))
- MANAGED – 這個(gè)配置幾乎沒做什么. 默認(rèn)情況下它會(huì)關(guān)閉連接薛躬。然而一些容器并不希望連接被關(guān)閉。
如果你正在使用 Spring + MyBatis秉剑,則沒有必要配置事務(wù)管理器泛豪,因?yàn)?Spring 模塊會(huì)使用自帶的管理器來覆蓋前面的配置。
數(shù)據(jù)源(dataSource)
連接數(shù)據(jù)庫(kù)
有三種內(nèi)建的數(shù)據(jù)源類型(也就是 type="[UNPOOLED|POOLED|JNDI]"):
-
UNPOOLED– 這個(gè)數(shù)據(jù)源的實(shí)現(xiàn)會(huì)每次請(qǐng)求時(shí)打開和關(guān)閉連接侦鹏。但是性能要求不高诡曙。(沒有池)
池:用完可以回收 - POOLED– 這種數(shù)據(jù)源的實(shí)現(xiàn)利用“池”的概念將 JDBC 連接對(duì)象組織起來,避免了創(chuàng)建新的連接實(shí)例時(shí)所必需的初始化和認(rèn)證時(shí)間略水。能使并發(fā) Web 應(yīng)用快速響應(yīng)請(qǐng)求价卤。(默認(rèn))
- JNDI
Mybatis默認(rèn)的事務(wù)管理器就是JDBC,連接池:POOLED
學(xué)會(huì)實(shí)用配置多套運(yùn)行環(huán)境渊涝。
4.3屬性(properties)
我們可以通過properties屬性來實(shí)現(xiàn)引用配置文件慎璧。
這些屬性可以在外部進(jìn)行配置床嫌,并可以進(jìn)行動(dòng)態(tài)替換。你既可以在典型的 Java 屬性文件中配置這些屬性胸私,也可以在 properties 元素的子元素中設(shè)置厌处。【db.properties】
編寫一個(gè)配置文件
db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&characterEncoding=UTF-8&useUnicode=true&serverTimezone=GMT
username=root
password=123456
在xml中岁疼,所有標(biāo)簽都可以規(guī)定其順序:properties阔涉,settings,typeAliases捷绒,typeHandlers瑰排,objectWraperFactory,reflectorFactory暖侨,plugins椭住,environment,databaseldProvider字逗,mappers
在核心配置文件中引入
<properties resource="db.properties">
<property name="password" value="123456"/>
</properties>
- 可以直接引入外部文件
- 可以直接在其中增加屬性配置
- 如果db.properties和核心配置文件中有同一字段京郑,優(yōu)先使用外部配置文件
4.4類型別名(typeAliases)
- 類型別名是為java類型設(shè)置一個(gè)短的名字。
- 存在的意義僅在于用來減少類完全限定名的冗余扳肛。
mybatis-config.xml
<!-- 可以給實(shí)體類起別名 -->
<typeAliases>
<typeAlias type="com.qwe.pojo.User" alias="User"/>
</typeAliases>
UserMapper.xml
<select id="getUserList" resultType="User">
select * from mybatis.user
</select>
- 也可以指定一個(gè)包名傻挂,MyBatis 會(huì)在包名下面搜索需要的 Java Bean,掃描實(shí)體類的包挖息,它的默認(rèn)別名就為這個(gè)類的類名,首字母小寫兽肤。
mybatis-config.xml
<typeAliases>
<package name="com.qwe.pojo"/>
</typeAliases>
UserMapper.xml
<select id="getUserList" resultType="user">
select * from mybatis.user
</select>
- 在實(shí)體類比較少的時(shí)候套腹,使用第一種方式,如果實(shí)體類十分多资铡,建議使用第二種电禀。第一種可以DIY別名,第二種不行笤休,如果非要改可以在實(shí)體類上面通過注解起別名尖飞。
@Alias("hello")
public class Author {
...
}
4.5設(shè)置
這是 MyBatis 中極為重要的調(diào)整設(shè)置,它們會(huì)改變 MyBatis 的運(yùn)行時(shí)行為店雅。
設(shè)置名 | 描述值 | 有效值 | 默認(rèn)值 |
---|---|---|---|
logImpl | 指定 MyBatis 所用日志的具體實(shí)現(xiàn)政基,未指定時(shí)將自動(dòng)查找。 | SLF4J / LOG4J(deprecated since 3.5.9)/ LOG4J2/ JDK_LOGGING/ COMMONS_LOGGING /STDOUT_LOGGING / NO_LOGGING | 未設(shè)置 |
cacheEnabled | 全局性地開啟或關(guān)閉所有映射器配置文件中已配置的任何緩存闹啦。 | true /false | true |
lazyLoadingEnabled | 延遲加載的全局開關(guān)沮明。當(dāng)開啟時(shí),所有關(guān)聯(lián)對(duì)象都會(huì)延遲加載窍奋。 特定關(guān)聯(lián)關(guān)系中可通過設(shè)置 fetchType 屬性來覆蓋該項(xiàng)的開關(guān)狀態(tài)荐健。 | true /false | false |
4.6其他配置
- typeHandlers(類型處理器)
- objectFactroy(對(duì)象工廠)
- plugins(插件)
* mybatis-generator-core
* mybatis-plus
* 通用mapper
4.7映射器(mappers)
需要告訴 MyBatis 到哪里去找到這些語(yǔ)句酱畅。最好的辦法是直接告訴 MyBatis 到哪里去找映射文件颓鲜。
MapperRegistry:注冊(cè)綁定我們的Mapper文件课锌;
方式一:使用相對(duì)于類路徑的資源引用
<mappers>
<mapper resource="com/qwe/dao/UserMapper.xml"/>
</mappers>
方式二:使用映射器接口實(shí)現(xiàn)類的完全限定類名
<mappers>
<mapper class="com.qwedao.UserMapper"/>
</mappers>
注意點(diǎn):
- 接口和他的Mapper配置文件必須同名
- 接口和他的Mapper配置文件必須在同一個(gè)包下
方式三:將包內(nèi)的映射器接口實(shí)現(xiàn)全部注冊(cè)為映射器
<mappers>
<package name="com.qwe.dao"/>
</mappers>
注意點(diǎn):
- 接口和他的Mapper配置文件必須同名
- 接口和他的Mapper配置文件必須在同一個(gè)包下
4.8生命周期和作用域
生命周期和作用域是至關(guān)重要的缤言,因?yàn)殄e(cuò)誤的使用會(huì)導(dǎo)致非常嚴(yán)重的并發(fā)問題锦积。
SqlSessionFactoryBulider:
- 一旦創(chuàng)建了SqlSessionFactory既琴,就不再需要它了
- 局部變量
SqlSessionFactory:
- 可以想象為:數(shù)據(jù)庫(kù)連接池
- SqlSessionFactory一旦被創(chuàng)建就應(yīng)該在應(yīng)用的運(yùn)行期間一直存在瓮孙,沒有任何理由丟棄它或者重新創(chuàng)建另一個(gè)實(shí)例卖漫。
- 因此SqlSessionFactory的最佳作用域是應(yīng)用作用域捞魁。
SqlSession:
- 連接到連接池的一個(gè)請(qǐng)求
- SqlSession 的實(shí)例不是線程安全的在张,因此是不能被共享的用含,所以它的最佳的作用域是請(qǐng)求或方法作用域。
-
用完之后需要趕緊關(guān)閉帮匾,否則資源被占用
需要關(guān)閉的原因
這里的每一個(gè)Mapper啄骇,就代表一個(gè)具體的業(yè)務(wù)。
5.解決屬性名和字段名不一致的問題
5.1問題
數(shù)據(jù)庫(kù)中的字段
新建一個(gè)項(xiàng)目瘟斜,拷貝之前的缸夹,測(cè)試實(shí)體類字段不一致的情況
User.java
public class User {
private int id;
private String name;
private String password;//原來是pwd
測(cè)試結(jié)果:User{id=1, name='張三', password='null'}
解決方法:
- 起別名
UserMapper.xml
<select id="getUserById" parameterType="int" resultType="User">
select id,name,pwd as password from mybatis.user where id =#{id};
</select>
4.2resultMap
結(jié)果集映射
UserMapper.xml
<!-- 結(jié)果集映射 -->
<resultMap id="UserMap" type="User">
<!-- column數(shù)據(jù)庫(kù)中的字段,property實(shí)體類中的屬性 -->
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserById" resultMap="UserMap">
select * from mybatis.user where id =#{id};
</select>
- resultMap元素是MyBatis中最重要最強(qiáng)大的元素
- ResultMap的設(shè)計(jì)思想是螺句,對(duì)于簡(jiǎn)單的語(yǔ)句根本不需要配置顯式的結(jié)果映射虽惭,而對(duì)于復(fù)雜一點(diǎn)的語(yǔ)句只需要描述他們的關(guān)系就行了。
- ResultMap最優(yōu)秀的地方在于蛇尚,雖然你已經(jīng)對(duì)它相當(dāng)了解了芽唇,但是根本就不需要顯式的用到他們。
6.日志
6.1 日至工廠
如果一個(gè)數(shù)據(jù)庫(kù)操作出現(xiàn)了異常取劫,我們需要排錯(cuò)匆笤,日志就是最好的助手。
![logImpl](https://upload-images.jianshu.io/upload_images
/27766806-953d0bf381a080ff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- SLF4J
- LOG4J【掌握】
- LOG4J2
- JDK_LOGGING
- STDOUT_LOGGING【掌握】
- NO_LOGGING
在Mybatis中具體使用哪一個(gè)日志實(shí)現(xiàn)谱邪,在設(shè)置中設(shè)置炮捧。
STDOUT_LOGGING標(biāo)準(zhǔn)日志輸出
mybatis-config.xml
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
6.2Log4j
什么是Log4j?
- Log4j是Apache的一個(gè)開源項(xiàng)目惦银,通過使用Log4j咆课,我們可以控制日志信息輸送的目的地是控制臺(tái)、文件扯俱、GUI組件
- 我們也可以控制每一條日志的輸出格式
- 通過定義每一條日志信息的級(jí)別书蚪,我們能夠更加細(xì)致地控制日志的生成過程。
- 通過一個(gè)配置文件來靈活地進(jìn)行配置蘸吓,而不需要修改應(yīng)用的代碼善炫。
1.先導(dǎo)入Log4j的包
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2.log4.properties
#將等級(jí)為DEBUG的日志信息輸出到console和file這兩個(gè)目的地,console和file的定義在下面的代碼
log4j.rootLogger = DEBUG,console,file
#控制臺(tái)輸出的相關(guān)設(shè)置
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.Threshole=DEBUG
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件輸出的相關(guān)設(shè)置
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/qwe.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
#日志輸出級(jí)別
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.配置log4j為日志的實(shí)現(xiàn)
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
4.log4j的使用:直接測(cè)試運(yùn)行剛才的查詢
簡(jiǎn)單使用
1.在要使用Log4j的類中库继,導(dǎo)入包import org.apache.log4j.Logger;
2.日志對(duì)象箩艺,參數(shù)為當(dāng)前類的class
static Logger logger = Logger.getLogger(UserDaoTest.class);
3.日志級(jí)別
logger.info("info:進(jìn)入了testLog4j");
logger.debug("debug:進(jìn)入了testLog4j");
logger.error("error:進(jìn)入了testLog4j");
7.分頁(yè)
7.1 使用Limit分頁(yè)
SELECT * from user limit startIndex,pagesize;//從第幾個(gè)開始窜醉,每頁(yè)顯示幾個(gè)
//SELECT * from user limit 2; #[0,2]
使用Mybatis實(shí)現(xiàn)分頁(yè)艺谆,核心SQL
1.接口
//分頁(yè)
List<User> getUserByLimit(Map<String,Integer> map);
2.Mapper.xml
<select id="getUserByLimit" parameterType="map" resultMap="UserMap">
select * from mybatis.user limit #{startindex},#{pagesize}
</select>
3.測(cè)試
@Test
public void getUserByLimit(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("startindex",0);
map.put("pagesize",2);
List<User> userList = mapper.getUserByLimit(map);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
7.2 RowBounds分頁(yè)
1.接口
//分頁(yè)2
List<User> getUserByRowBounds();
2.Mapper.xml
<select id="getUserByRowBounds" resultMap="UserMap">
select * from mybatis.user
</select>
3.測(cè)試
@Test
public void getUserByRowBounds(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//RowBounds實(shí)現(xiàn)
RowBounds rowBounds = new RowBounds(1, 2);
//通過java代碼層面實(shí)現(xiàn)分頁(yè)
List<User> userList = sqlSession.selectList("com.qwe.dao.UserMapper.getUserByRowBounds",null,rowBounds);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
7.3分頁(yè)插件
8.使用注解開發(fā)
8.1面向接口編程
8.2 使用注解開發(fā)
1.注解在接口上實(shí)現(xiàn)
public interface UserMapper {
@Select("select * from user")
List<User> getUsers();
}
2.需要在核心配置文件中綁定接口榨惰!
<mappers>
<mapper class="com.qwe.dao.UserMapper"/>
</mappers>
3.測(cè)試
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//底層主要應(yīng)用反射
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.getUsers();
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
本質(zhì):反射機(jī)制實(shí)現(xiàn)
底層:動(dòng)態(tài)代理
Mybatis詳細(xì)的流程
配置文件-工具類-實(shí)現(xiàn)類-測(cè)試類
Resources獲取加載全局配置文件--->實(shí)例化SqlSessionFactoryBuilder構(gòu)造器--->解析配置文件流XMLConfigBuilder--->Configuration所有的配置信息--->SqlSessionFactory實(shí)例化--->transaction事務(wù)管理--->創(chuàng)建executor執(zhí)行器--->創(chuàng)建sqlSession--->實(shí)現(xiàn)CRUD(有可能回滾到事務(wù)管理器)--->查看是否執(zhí)行成功(不成功回滾)--->提交事務(wù)--->關(guān)閉
8.3 CRUD
我們可以在工具類創(chuàng)建的時(shí)候?qū)崿F(xiàn)自動(dòng)提交事務(wù)!
MybatisUtils.java
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession(true);
}
編寫接口静汤,增加注釋
public interface UserMapper {
@Select("select * from user")
List<User> getUsers();
//方法存在多個(gè)參數(shù)琅催,所有的參數(shù)前面必須加上@Param("id")注解
@Select("select * from user where id =#{id}")
User getUserByID(@Param("id") int id);
@Insert("insert into user(id,name,pwd) values(#{id},#{name},#{password})")
int addUser(User user);
@Update("update user set name=#{name},pwd=#{password} where id = #{id}")
int updateUser(User user);
@Delete("delete from user where id = #{id}")
int deleteUser(@Param("id") int id);
}
測(cè)試類
注意:我們必須要將接口注冊(cè)綁定到我們的核心配置文件中!
public class UserMapperTest {
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//底層主要應(yīng)用反射
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// List<User> users = mapper.getUsers();
// for (User user : users) {
// System.out.println(user);
// }
// User userByID = mapper.getUserByID(1);
// System.out.println(userByID);
// mapper.addUser(new User(5,"hello","123456"));
// mapper.updateUser(new User(5,"aaa","123456"));
mapper.deleteUser(5);
sqlSession.close();
}
}
關(guān)于@Param()注解
- 基本類型的參數(shù)或者String類型虫给,需要加上
- 引用類型不需要加
- 如果只有一個(gè)基本類型的話藤抡,可以忽略,但是建議大家都加上
- 我們?cè)赟QL中引用的就是我們這里的@Param("id")中設(shè)定的屬性名
9 Lombok
使用步驟:
1.在IDEA中安裝Lombok插件
2.在項(xiàng)目中導(dǎo)入lombok的jar包
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
3.在實(shí)體類上加lombok注解
@Getter and @Setter
@FieldNameConstants 字段屬性常量
@ToString
@EqualsAndHashCode
@AllArgsConstructor, 全部的構(gòu)造參數(shù)@RequiredArgsConstructor and @NoArgsConstructor無參構(gòu)造
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors鏈?zhǔn)讲僮?@Wither
@With
@SneakyThrows
@Data:無參構(gòu)造抹估,get缠黍、set、tostring药蜻、hashcode瓷式、equals
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
@ToString
4.優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
- 能通過注解的形式自動(dòng)生成構(gòu)造器,getter/setter语泽、equals贸典。hashcode、toString等方法踱卵,提高了一定的開發(fā)效率
- 讓代碼變得簡(jiǎn)潔廊驼,不用過多的去關(guān)注相應(yīng)的方法
- 屬性做修改時(shí),也簡(jiǎn)化了維護(hù)為這些屬性所生成的getter/setter方法等
缺點(diǎn): - 不支持多種參數(shù)構(gòu)造器的重載
- 雖然省去了手動(dòng)創(chuàng)建getter/setter方法的麻煩颊埃,但大大降低了源代碼的可讀性和完整性蔬充,降低了閱讀源代碼的舒適度。
10.多對(duì)一處理
多對(duì)一:
- 多個(gè)學(xué)生班利,對(duì)應(yīng)一個(gè)老師
- 對(duì)于學(xué)生這邊而言,多個(gè)學(xué)生關(guān)聯(lián)一個(gè)老師榨呆。多對(duì)一
- 對(duì)于老師而言罗标,集合,一個(gè)老師有很多學(xué)生积蜻。一對(duì)多
SQL:
CREATE TABLE `teacher`(
`id`INT(10)NOT NULL,
`name`VARCHAR(30)DEFAULT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO teacher(`id`,`name`)VALUES(1,'秦老師');
CREATE TABLE `student`(
`id`INT(10)NOT NULL,
`name`VARCHAR(30)DEFAULT NULL,
`tid` INT(10)DEFAULT NULL,
KEY`fkid`(`tid`),
CONSTRAINT`fktid`FOREIGN KEY(`tid`)REFERENCES`teacher`(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO `student`(`id`,`name`,`tid`)VALUES('1','小明','1');
INSERT INTO `student`(`id`,`name`,`tid`)VALUES('2','小紅','1');
INSERT INTO `student`(`id`,`name`,`tid`)VALUES('3','小張','1');
INSERT INTO `student`(`id`,`name`,`tid`)VALUES('4','小李','1');
INSERT INTO `student`(`id`,`name`,`tid`)VALUES('5','小王','1');
測(cè)試環(huán)境搭建
1.導(dǎo)入lombok
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
2.新建實(shí)體類Teacher闯割,Student
@Data
public class Teacher {
private int id;
private String name;
}
@Data
public class Student {
private int id;
private String name;
//學(xué)生需要關(guān)聯(lián)一個(gè)老師
private Teacher teacher;
}
3.建立Mapper接口
public interface TeacherMapper {
@Select("select * from teacher where id = #{tid}")
Teacher getTeacher (@Param("tid") int id);
}
public interface StudentMapper {
}
4.建立Mapper.xml文件
<?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="com.qwe.dao.TeacherMapper">
</mapper>
<?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="com.qwe.dao.StudentMapper">
</mapper>
5.在核心配置文件中綁定注冊(cè)我們的Mapper接口或者文件
<mappers>
<mapper class="com.qwe.dao.TeacherMapper"/>
<mapper class="com.qwe.dao.StudentMapper"/>
</mappers>
6.測(cè)試查詢是否能夠成功
public class MyTest {
public static void main(String[] args) {
SqlSession sqlSession = MybatisUtils.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher = mapper.getTeacher(1);
System.out.println(teacher);
sqlSession.close();
}
}
按照查詢嵌套處理
<!-- 思路:查詢所有學(xué)生信息,根據(jù)查詢出來的學(xué)生的tid尋找對(duì)應(yīng)的老師 -->
<select id="getStudent" resultMap="StudentTeacher">
select * from student;
</select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!-- 復(fù)雜屬性竿拆,我們需要單獨(dú)處理 對(duì)象:association 集合:collection -->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="Teacher">
select * from teacher where id = #{id}
</select>
按照結(jié)果嵌套處理
<select id="getStudent2" resultMap="StudentTeacher2">
select s.id sid,s.name sname,t.name tname
from student s,teacher t
where s.tid =t.id
</select>
<resultMap id="StudentTeacher2" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
回顧Mysql多對(duì)一查詢方式:
- 子查詢
- 聯(lián)表查詢
11.一對(duì)多處理
比如:一個(gè)老師擁有多個(gè)學(xué)生宙拉!
對(duì)于老師而言,就是一對(duì)多的關(guān)系丙笋。
環(huán)境搭建(同多對(duì)一)
實(shí)體類
@Data
public class Student {
private int id;
private String name;
//學(xué)生只有一個(gè)老師
private int tid;
}
@Data
public class Teacher {
private int id;
private String name;
//一個(gè)老師擁有多個(gè)學(xué)生
private List<Student> students;
}
<!-- 按結(jié)果嵌套查詢 -->
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid,s.name sname,t.name tname,t.id tid
from student s,teacher t
where s.tid=t.id and t.id=#{tid}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!--負(fù)載的屬性我們需要單獨(dú)處理 對(duì)象association 集合collection
javaType ="" 指定屬性的類型谢澈!
集合中的泛型信息煌贴,我們使用ofType獲取
-->
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>