MyBatis
1、簡介
1.1什么是MyBatis
-
MyBatis 是一款優(yōu)秀的持久層框架
-
它支持自定義 SQL、存儲過程以及高級映射
-
MyBatis 免除了幾乎所有的 JDBC 代碼以及設(shè)置參數(shù)和獲取結(jié)果集的工作
-
MyBatis 可以通過簡單的 XML 或注解來配置和映射原始類型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 對象)為數(shù)據(jù)庫中的記錄。
-
開源框架
如何獲得Mybatis?
- maven倉庫
- github
- 中文文檔
1.2持久化
數(shù)據(jù)持久化
- 持久化就是將程序的數(shù)據(jù)再持久狀態(tài)和順勢在狀態(tài)轉(zhuǎn)化的過程
- 內(nèi)存:斷電即失
- 數(shù)據(jù)庫(jdbc),io文件持久化
- 生活:冷藏
為什么需要持久化
-
有一些對象,不能讓他丟掉
-
內(nèi)存太貴
1.3持久層
Dao層,Service層,Controller層
- 完成持久化工作的代碼塊
- 層是界限十分明顯的
1.4為什么需要MyBatis
- 幫助程序員把數(shù)據(jù)存入數(shù)據(jù)庫
- 方便
- 傳統(tǒng)的jdbc代碼太復(fù)雜–簡化,框架,自動化
- 不用mybatis也可以,技術(shù)沒有高低之分
- 優(yōu)點(diǎn):很多
2、第一個(gè)MyBatis程序
思路:搭建環(huán)境—>導(dǎo)入Mybatis
2.1、搭建環(huán)境
數(shù)據(jù)庫
create database mybatis;
use mybatis;
create table user(
id int primary key not null ,
name char(20) not null,
pwd char(20) not null
)engine=InnoDB DEfault charset=utf8;
alter table user change id id int AUTO_INCREMENT;
insert into `user`(name,pwd) values
("楊華","123456"),
("劉德華","123456")
新建項(xiàng)目
-
新建一個(gè)普通的maven項(xiàng)目
-
刪除src目錄
-
導(dǎo)入maven依賴
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>mybatis-study</artifactId> <version>1.0-SNAPSHOT</version> <!-- 父工程--> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <!-- 導(dǎo)入依賴 --> <dependencies> <!-- mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.30</version> </dependency> <!-- mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <!-- junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.1</version> <scope>test</scope> </dependency> </dependencies> </project>
2.2、創(chuàng)建一個(gè)模塊
-
編寫mybatis的核心配置文件-連接數(shù)據(jù)庫(后續(xù)可以使用properties)
<!--核心配置環(huán)境--> <configuration> <environments default="development"> <!--其中一個(gè)環(huán)境--> <environment id="development"> <!--事務(wù)管理--> <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=UTF-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> </configuration>
-
編寫一個(gè)mybatis工具類
- 官網(wǎng)三部曲–有些地方報(bào)錯(cuò)需要添加try-catch
- 路徑記得填自己的
String resource = "org/mybatis/example/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//獲取SqlSession對象 從 SqlSessionFactory //SqlSession 提供了在數(shù)據(jù)庫執(zhí)行 SQL 命令所需的所有方法 public class MyBatisUtils { private static SqlSessionFactory sqlSessionFactory; String resource = "org/mybatis/example/mybatis-config.xml"; InputStream inputStream; { try { //使用mybatis獲取 inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } //既然有了 SqlSessionFactory,顧名思義,我們可以從中獲得 SqlSession 的實(shí)例 // SqlSession 提供了在數(shù)據(jù)庫執(zhí)行 SQL 命令所需的所有方法 public static SqlSession getsqlSession(){ return sqlSessionFactory.openSession(); //sqlSession可以操作數(shù)據(jù)庫 } }
2.3、編寫代碼
- 實(shí)體類(后續(xù)很多get,set,無參構(gòu)造和有參構(gòu)造,方法可以注解開發(fā))
package com.yang.pojo;
//實(shí)體類
public class User {
private int id;
private String name;
private String pwd;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public String getPwd() {
return pwd;
}
public User(){
}
public User(int id,String name,String pwd){
this.id = id;
this.name = name;
this.pwd = pwd;
}
}
- Dao接口
public interface UserDao {
List<User> getUserList();
}
-
接口實(shí)現(xiàn)類由原來UserDaoImpl轉(zhuǎn)變?yōu)橐粋€(gè)Mapper配置文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace綁定一個(gè)dao/Mapper接口--> <mapper namespace="com.yang.dao.UserDao"> <!--查詢語句--> <select id="getUrlList" resultType="com.yang.pojo.User"> select * from mybatis.user; </select> </mapper>
2.4、測試
注意點(diǎn):Type interface…錯(cuò)誤(100%會遇到):沒有配置resourse
<!--在build中配置resoureces,來防止我們資源導(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測試
package com.yang.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; //獲取SqlSession對象 從 SqlSessionFactory //SqlSession 提供了在數(shù)據(jù)庫執(zhí)行 SQL 命令所需的所有方法 public class MyBatisUtils { private static SqlSessionFactory sqlSessionFactory; static { try { String resource = "mybatis-config.xml"; InputStream inputStream= Resources.getResourceAsStream(resource); //使用mybatis獲取inputStream sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } //既然有了 SqlSessionFactory,顧名思義,我們可以從中獲得 SqlSession 的實(shí)例 // SqlSession 提供了在數(shù)據(jù)庫執(zhí)行 SQL 命令所需的所有方法 public static SqlSession getsqlSession(){ return sqlSessionFactory.openSession(); //sqlSession可以操作數(shù)據(jù)庫 //sqlSession } }
3、curd
1.namespace
namespace中的包名要和Dap/Mapper中的一致
2.選擇,查詢語句;
- id就是對應(yīng)的namespace中的方法名
- resultType:sql語句返回值
- parameter:參數(shù)類型
select查詢案例
com\yang\dao\UserMapper.xml
<select id="getUserById" parameterType="int" resultType="com.yang.pojo.User">
select * from mybatis.user where id=#{id};<!--id為調(diào)用dao里面的方法,select里面是sql語句,傳入?yún)?shù)id-->
</select>
com\yang\dao\UserDaoTest.java
public interface UserMapper {
User getUserById(int id);//定義方法
}
com\yang\dao\UserDaoTest.java
public class UserDaoTest {
@Test
public void test2(){
//獲得sqlsession對象
SqlSession sqlSession = MyBatisUtils.getsqlSession();
//執(zhí)行
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUserById(1);//調(diào)用dao方法
System.out.println(user);
sqlSession.close();
}
}
增刪改需要用事務(wù)
sqlsession.commit()
兩個(gè)符號的區(qū)別:#和$
盡量多用#方式,少用$方式
#{變量名}可以進(jìn)行預(yù)編譯、類型匹配等操作,#{變量名}會轉(zhuǎn)化為jdbc的類型。
select * from tablename where id = #{id}
假設(shè)id的值為12,其中如果數(shù)據(jù)庫字段id為字符型,那么#{id}表示的就是'12',如果id為整型,那么id就是12,并且MyBatis會將上面SQL語句轉(zhuǎn)化為jdbc的select * from tablename where id=?,把?參數(shù)設(shè)置為id的值。
${變量名}不進(jìn)行數(shù)據(jù)類型匹配,直接替換。
select * from tablename where id = ${id}
如果字段id為整型,sql語句就不會出錯(cuò),但是如果字段id為字符型, 那么sql語句應(yīng)該寫成select * from table where id = '${id}'。
#方式能夠很大程度防止sql注入。
$方式無法方式sql注入。
$方式一般用于傳入數(shù)據(jù)庫對象,例如傳入表名。
一個(gè)小bug是如果用$就需要非整型中加引號(不加會報(bào)錯(cuò)),如果是#就不用(加了會報(bào)錯(cuò))
3.增刪改
增刪改案例
com\yang\dao\UserMapper.xml–這里的#{}里面的內(nèi)容可以直接寫傳進(jìn)去對象的類屬性
<insert id="addUser" parameterType="com.yang.pojo.User" >
insert into mybatis.user values(#{id},'#{name}',#{pwd})
</insert>
<update id="updateUser" parameterType="com.yang.pojo.User">
update mybatis.user set name='#{name}',pwd =#{pwd} where id=#{id}
</update>
<delete id="deleteUser" parameterType="int">
delete from mybatis.user where id=#{id}
</delete>
com\yang\dao\UserDaoTest.java
public class UserDaoTest {
@Test
public void test3(){
//獲得sqlsession對象
SqlSession sqlSession = MyBatisUtils.getsqlSession();
//執(zhí)行
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.addUser(new User(11,"流","1234"));
sqlSession.commit();
sqlSession.close();
test();
}
@Test
public void test4(){
SqlSession sqlSession = MyBatisUtils.getsqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.updateUser(new User(10, "fei", "12345"));
sqlSession.commit();
sqlSession.close();
test();
}
@Test
public void test5(){
SqlSession sqlSession = MyBatisUtils.getsqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.deleteUser(11);
sqlSession.commit();
sqlSession.close();
}
}
com\yang\dao\UserMapper.java
public interface UserMapper {
int addUser(User user);
//修改用戶
int updateUser(User user);
//刪除用戶
int deleteUser(int id);
}
4.map代替User對象
優(yōu)點(diǎn)
- 自定義鍵的名字
- 自定義傳入數(shù)據(jù)(不一定非要整個(gè)對象傳進(jìn)去,尤其是可能只是需要修改,需要?jiǎng)h除)
<insert id="addUser2" parameterType="map" >
insert into user values(#{userid},#{username},#{userpwd});
</insert>
int addUser2(Map<String,Object> map);
@Test
public void test6(){
SqlSession sqlSession = MyBatisUtils.getsqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String,Object>map = new HashMap<String,Object>();
map.put("userid",13);
map.put("username","ylw");
map.put("userpwd","ylw");
mapper.addUser2(map);
sqlSession.commit();
sqlSession.close();
}
Map傳遞參數(shù)直接在sql中取出key就可以了
5.模糊查詢
模糊查詢:寫通配符語句
防sql注入–后臺把用戶能傳的值限定好
select * from id=?(1 or 1=1);
select * from mybatis.user where name like %"#{value}"%
4.配置解析
1、核心配置文件
-
mybatis-config.xml
configuration(配置) properties(屬性) settings(設(shè)置) typeAliases(類型別名) typeHandlers(類型處理器) objectFactory(對象工廠) plugins(插件) environments(環(huán)境配置) environment(環(huán)境變量) transactionManager(事務(wù)管理器) dataSource(數(shù)據(jù)源) databaseIdProvider(數(shù)據(jù)庫廠商標(biāo)識) mappers(映射器)
2、環(huán)境配置
MyBatis 可以配置成適應(yīng)多種環(huán)境
不過要記?。罕M管可以配置多個(gè)環(huán)境,但每個(gè) SqlSessionFactory 實(shí)例只能選擇一種環(huán)境。–default制定
<!-- 事務(wù)管理--JDBC或者manage -->
<transactionManager type="JDBC"/>
<!-- 數(shù)據(jù)源 -->
<dataSource type="POOLED">
</dataSource>
學(xué)會使用配置多套運(yùn)行環(huán)境!
mybatis默認(rèn)事務(wù)管理器是jdbc,連接池:POOLED
3、屬性(properties)
我們可以通過properties屬性來實(shí)現(xiàn)引用配置而文件
這些屬性都是可以外部配置且可動態(tài)替換的,既可以在典型的java屬性文件中配置,也可以通過properties元素的子元素來傳遞–[db.properties]
db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username=root
password=123456
在xml中,所有的標(biāo)簽有順序
<properties resource="db.properties">
<property name="username" value="password"></property>
</properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<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>
- 可以直接引入外部文件
- 可以在其中增加屬性配置
- 如果兩個(gè)文件有同一個(gè)字段,優(yōu)先使用外部配置文件
4、類型別名(typeAliases)
- 類型別名可為 Java 類型設(shè)置一個(gè)縮寫名字。
- 它僅用于 XML 配置,意在降低冗余的全限定類名書寫。
給實(shí)體類起別名
<typeAliases>
<typeAlias type="com.yang.pojo.User" alias="User"/>
</typeAliases>
也可以指定一個(gè)包名,MyBatis 會在包名下面搜索需要的 Java Bean
掃描實(shí)體類的包,他的默認(rèn)別名就為這個(gè)類的類名,首字母小寫
<package name="com.yang.pojo"/>
- 實(shí)體類比較少用第一種,比較多用第二種
- 第一種可以自定義(diy)別名,第二種不行(除非使用注解)
@Alias("hello")
//實(shí)體類
public class User {
5、設(shè)置
6、其他配置
-
類型處理器(typeHandlers)
-
對象工廠(objectFactory)
-
plugins
- mybatis-generater-core
- mybatis-plus
- 通用mapper
7、映射器(mapper)
MapperRegister:注冊綁定我們的Mapper文件
<!-- 每一個(gè)Mapper.xml都需要在mybatis核心配置文件中注冊 -->
推薦第一種
方式一:
<mappers>
<mapper resource="com/yang/dao/UserMapper.xml"/>
</mappers>
方式二:
<mappers>
<mapper class="com/yang/dao/UserMapper"/>
</mappers>
注意點(diǎn)
- 接口和他的mapper下面必須同名!
- 接口和他的mapper配置文件必須在同一個(gè)包下!
方式三:使用掃描包進(jìn)行注入綁定
<package name="com/yang/dao"/>
注意點(diǎn)
- 接口和他的mapper項(xiàng)目必須同名!
- 接口和他的mapper配置文件必須在同一個(gè)包下!
8、生命周期及作用域
5、屬性名和字段名不一致
1、問題
類型處理器
解決方法
- 起別名
- resultemap
2、resultemap
結(jié)果集映射
id name pwd
id name password
<!--如果字段名一樣,可以不用寫-->
<resultMap id="UserMap" type="User">
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserList" resultType="UserMap">
select * from mybatis.user;
</select>
不需要的字段可以刪除
通過映射把可以不用寫和數(shù)據(jù)庫一樣的字段
- resultMap元素是MyBatis中最重要最強(qiáng)大的元素
- 設(shè)計(jì)思想是,對于簡單的語句根本不需要配置顯式的結(jié)果映射,對于復(fù)雜的語句,只需描述他們的關(guān)系就行了
- 雖然你對它相當(dāng)了解,但是不需要顯式的用到他們
- 要是世界總是這么簡單就好了
6、日志
6.1 日志工廠
logImpl
- SLF4J - LOG4J
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- STDOUT_LOGGING[掌握]
- NO_LOGGING
name和value必須完全一樣(區(qū)分大小寫并且不能有空格)
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"></setting>
</settings>
在mybatis中具體使用哪一個(gè)日志實(shí)現(xiàn),在設(shè)置中設(shè)定
STDOUT_LOGGING標(biāo)準(zhǔn)日志輸出
在mybatis核心配置文件中配置我們的日志
6.2 什么是LOG4J2
-
Log4j是Apache的一個(gè)開源項(xiàng)目,通過使用Log4j,我們可以控制日志信息輸送的目的地是控制臺、文件、GUI組件
-
我們也可以控制每一條日志的輸出格式
-
通過定義每一條日志信息的級別,我們能夠更加細(xì)致地控制日志的生成過程
可以通過一個(gè)配置文件來靈活地進(jìn)行配置,而不需要修改應(yīng)用的代碼。
7、分頁
為什么分頁
- 減少數(shù)據(jù)的處理量
使用limit分頁
select * from user limit [start,] len;#start可以省略不寫
使用mybatis實(shí)現(xiàn)分頁,核心就是limit
- 接口
- Mapper.xml
- 測試
別名
接口
public interface UserMapper {
List<User> getUserList();
List<User> getUserByLimit(Map<String,Integer> map);//多用map,好用
}
映射
<select id="getUserByLimit" parameterType="map" resultType="user">
select * from mybatis.user limit #{startIndex},#{pageSize}
</select>
測試
@Test
public void getUserLIimit(){
SqlSession sqlSession = MyBatisUtils.getsqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Integer> map = new HashMap<>();
map.put("startIndex",0);
map.put("pageSize",2);
List<User> userList = (List<User>) mapper.getUserByLimit(map);
for (User user:userList){
System.out.println(user);
}
}
8、注解開發(fā)
8.1、面向接口編程
原因:解耦
關(guān)于接口的了解:
- 定義與實(shí)現(xiàn)的分離
- 本身反映了系統(tǒng)設(shè)計(jì)人員對系統(tǒng)的抽象理解
- 接口有兩類
- 對一個(gè)個(gè)體的抽象,對應(yīng)一個(gè)抽象體
- 抽象面
- 一個(gè)抽象體可能有多個(gè)抽象面
三和面向區(qū)別
- 對象為單位
8.2、注解開發(fā)–主要是靠反射機(jī)制(java基礎(chǔ)有)
對于簡單項(xiàng)目可以使用注解開發(fā),但是如果復(fù)雜一點(diǎn)兒的就力不從心了
1、注解在接口實(shí)現(xiàn)
public interface UserMapper {
@Select("select * from user")
List<User> getUserList();
}
2、核心配置文件綁定接口
<mappers>
<mapper class="com.yang.dao.UserMapper"/>
</mappers>
3、測試
本質(zhì):反射機(jī)制實(shí)現(xiàn)
底層:動態(tài)代理
mybatis詳細(xì)執(zhí)行流程
xxx
8.3、注解crud
可以設(shè)置自動提交事務(wù)
public static SqlSession getsqlSession(){
return sqlSessionFactory.openSession(true);
}
編寫接口
public interface UserMapper {
@Select("select * from user")
List<User> getUserList();
//多個(gè)元素一定要加@Param("xx")注解
@Select("select * from user where id=#{id}")
User getUserById(@Param("id") int id2);//后面的名字不重要
}
測試類:
我們必須要將接口注冊綁定到我們的項(xiàng)目配置核心
關(guān)于@Param()注解
- 基本類型參數(shù)或者String類型,需要加上
- 引用類型不用加
- 如果只有一個(gè)基本類型的話,可以忽略,但是建議大家都加上
- 我們在sql中引用的就是我們這里的@Param設(shè)定的屬性名
9、Lombok
Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java.Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.
Lombok是一個(gè)Java庫,能自動插入編輯器并構(gòu)建工具,簡化Java開發(fā)。通過添加注解的方式,不需要為類編寫getter或eques方法,同時(shí)可以自動化日志變量。官網(wǎng)鏈接
- java library
- plugs
- build tools
- with one annotation your class
使用步驟
- 下載插件
-
導(dǎo)入jar包
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.4</version> <scope>provided</scope> </dependency>
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass
Lombok config system
Code inspections
Refactoring actions (lombok and delombok)
@Data:無參構(gòu)造,Setter,Getter,ToString,Equils,全都包括了
@Data
@AllArgsConstructor
@NoArgsConstructor
//上面一般就是下面的集合
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode
@ToString
10、多對一處理
10.1、復(fù)雜查詢環(huán)境搭建
1、導(dǎo)入lombok
2、新建實(shí)體類Teacher,Student
3、建立Mapper接口
4、建立Mapper.xml文件
5、在核心配置文件中綁定注冊我們的接口或者文件!【方式很多,隨便選】
6、測試查詢是否成功
resultMap–找到對應(yīng)的字段
10.2、按照查詢嵌套處理
復(fù)雜字段(多表查詢?nèi)缦拢?/p>
查詢的是一個(gè)對象
10.3、按照結(jié)果嵌套處理
嵌套里面再嵌套(結(jié)果集里是一個(gè)對象就用一個(gè)association)
回顧mysql多對一查詢方式
- 子查詢
- 連表查詢
11、一對多
一個(gè)老師,多個(gè)學(xué)生
對象用association,集合用collection
結(jié)果嵌套處理
實(shí)體類
@Data
public class Teacher {
private int id;
private String name;
private List<Student> students;
}
接口
//獲取制定老師下面的所有學(xué)生信息
Teacher getTeacher(@Param("tid") int id);
映射
<select id="getTeacher" resultMap="TeacherStudent">
select t.id tid,t.name tname,s.id sid,s.name sname
from mybatis.teacher t,mybatis.student s
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ú)處理 對象:association,集合Lcollection-->
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
測試
查詢嵌套處理
實(shí)體類相同,接口相同
映射
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from mybatis.teacher where id=#{tid}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByteacherId" column="id">
</collection>
</resultMap>
<select id="getStudentByteacherId" resultType="Student" >
select * from mybatis.student where tid=#{tid}
</select>
小結(jié)
- 關(guān)聯(lián)–association【多對一】
- 集合–collection【一對多】
- javatype & oftype
- javatype是制定實(shí)體類種屬性的類型
- oftype用來指定映射到List或者集合中的pojo類型,泛型中的約束類型
注意點(diǎn):
- 保證sql的可讀性
- 盡量保證通俗易懂
- 注意一對多和多對一中,屬性名和字段的問題
- 如果問題不好排查,可以使用日志
- 盡量保證文件的
面試高頻
- mysql引擎
- InnoDB
- 索引
- 索引優(yōu)化
12、動態(tài)SQL
動態(tài)SQL就是根據(jù)不同條件生成不同的SQL語句
- 利用動態(tài) SQL,可以徹底擺脫這種痛苦
<select id="findActiveBlogWithTitleLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
</select>
1、搭建環(huán)境
create table `blog`(
`id` varchar(20)not null comment '博客id',
`title` varchar(100) not null,
`author` varchar(30)not null ,
`create_time` datetime not null ,
`views` int(30) not null);
創(chuàng)建一個(gè)基礎(chǔ)工程
- 導(dǎo)包
- 編寫配置文件
@Data
public class Blog {
private int id;
private String title;
private String author;
private Date createTime;
private int views;
}
- 編寫實(shí)體類
- 編寫實(shí)體類對應(yīng)的Mapper接口和Mapper.xml
2、IF
不加where標(biāo)簽
<select id="queryBlogIF" parameterType="map" resultType="map">
select * from mybatis.blog
<if test="title != null">
and title like #{title}
</if>
<if test="author !=null" >
and author =#{author}
</if>
</select>
3、choose(when other)
只要一個(gè),選擇滿足的一個(gè),都不滿足走ontherwise
<select id="queryBlogChoose" resultType="map" parameterType="map">
select * from mybatis.blog
<where>
<choose>
<when test="title !=null">
title = #{title}
</when>
<when test="author !=null">
and author= #{author}
</when>
<otherwise>
and views =#{views}
</otherwise>
</choose>
</where>
</select>
4、trim()
加了where,set標(biāo)簽(沒有where可以,但是不安全)
where記得加and,它會幫我們刪除多余的and
<select id="queryBlogIF" parameterType="map" resultType="map">
select * from mybatis.blog
<where>
<if test="title != null">
and title like #{title}
</if>
<if test="author !=null">
and author =#{author}
</if>
</where>
</select>
set就是修改的部分,記得加逗號,它會幫你去除多余的逗號
<update id="updateBlog" parameterType="map">
update mybatis.blog
<set>
<if test="title !=null">
title=#{title},
</if>
<if test="author !=null">
author=#{author},
</if>
</set>
<where>
id=#{id}
</where>
</update>
可以用trim定制
sql片段:
抽取一些常用的語句,單獨(dú)作為sql片段
- sql抽取
<sql id="if-title-author">
<if test="title != null">
and title like #{title}
</if>
<if test="author !=null">
and author =#{author}
</if>
</sql>
- include引用
<select id="queryBlogIF" parameterType="map" resultType="map">
select * from mybatis.blog
<where>
<include refid="if-title-author"></include>
</where>
</select>
注意事項(xiàng):
- 最好基于表單來定義sql片段
- 不要存在where標(biāo)簽
foreach
sql
13、緩存
13.1、簡介
查詢:連接數(shù)據(jù)庫,耗資源!
一次查詢的結(jié)果,給他暫存在一個(gè)可以直接取到的地方-->內(nèi)存:緩存
當(dāng)再次訪問相同數(shù)據(jù)的啥時(shí)候,直接走緩存,就不用走數(shù)據(jù)庫了
1、什么是緩存cache
- 存在內(nèi)存里面的臨時(shí)數(shù)據(jù)
- 將用戶經(jīng)常查詢的數(shù)據(jù)放進(jìn)緩存
2、為什么使用緩存
- 減少和數(shù)據(jù)庫的交互次數(shù),減少系統(tǒng)開銷,提升系統(tǒng)效率
3、什么樣的數(shù)據(jù)能使用緩存
- 經(jīng)常使用并且不經(jīng)常改變的數(shù)據(jù)
- 反過來就不要了
13.2、Mybatis緩存
- MyBatis包含一個(gè)非常強(qiáng)大的查詢緩存特性,他可以非常方便的定制和配置緩存,緩存可以極大的提高查詢效率
- MyBatis默認(rèn)兩級緩存:一級和二級
- 默認(rèn)只有一級緩存開啟
- 二級緩存需要手動開啟和配置
- 為了提高擴(kuò)展性,MyBatis定義了緩存接口Cache,我們可以通過接口定義cache緩存
13.3、一級緩存
一級緩存又叫本地緩存:SqlSession(默認(rèn)開啟)
- 與數(shù)據(jù)庫同一次會話期間查詢到的數(shù)據(jù)回放到本地緩存中。
- 以后如果需要獲取相同的數(shù)據(jù),直接從緩存中拿,沒必要再去查數(shù)據(jù)庫
測試步驟
- 開啟日志
- 測試在一個(gè)Session中查詢兩次相同記錄
- 查看日志輸出
緩存失效的情況
-
查詢不同的東西
-
增刪改
-
查詢不同的Mapper
-
手動清楚緩存
sqlSession.clear()
總結(jié):一級緩存默認(rèn)開啟,可以看作是一個(gè)map,把數(shù)據(jù)放進(jìn)去,每次訪問都會給你這個(gè)數(shù)據(jù)
13.4、二級緩存
-
二級緩存又叫全局緩存,一級緩存作用域太低了,所以誕生了二級緩存
-
基于namespace級別的緩存,一個(gè)名稱空間對應(yīng)一個(gè)二級緩存
-
工作機(jī)制
- 一個(gè)會話查詢一條數(shù)據(jù),這個(gè)數(shù)據(jù)就會被放到當(dāng)前會話的一級緩存中
- 二u過當(dāng)前會話關(guān)閉了,這個(gè)會話對應(yīng)的一級緩存就沒了,但是我們想要的是,會話關(guān)閉了,一級緩存中的數(shù)據(jù)被保存到二級緩存
- 新的會話查詢信息,就可以從二級緩存中獲取內(nèi)容
- 不同的mapper查出的數(shù)據(jù)會被放到對應(yīng)的緩存(map)中
開啟緩存
開啟默認(rèn)顯示緩存
<setting name="cacheEnabled" value="true"></setting>
<cache/>
在要使用二級緩存的時(shí)候開啟
<cache/>
也可以自定義一些參數(shù)
<cache eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
一級緩存關(guān)閉,二級緩存開啟
sqlsession.close()
-
測試
-
問題:我們要將實(shí)體類序列化!否則會報(bào)錯(cuò)
public class User implements Serializable{}
-
小結(jié)
- 只要開啟了二級緩存,在同一個(gè)Mapper下就有效
- 所有的數(shù)據(jù)都會先放在一級緩存中
- 只有當(dāng)會話提交或者關(guān)閉的時(shí)候,才會提交到二級緩沖中
13.5、MyBatis緩存原理
緩存順序
- 先走二級緩存(如果開啟了的話)
- 再看一級緩存
- 然后看數(shù)據(jù)庫有沒有
- 最后把數(shù)據(jù)放進(jìn)緩存(如果沒在緩存里面找到的話)
13.6、自定義緩存ehcache
Ehcache是一種廣泛使用的開源java分布式緩存,主要面向通用緩存
-
先導(dǎo)包(百度–包名 maven)
-
自定義文件(xml)
MyBatis總結(jié)
Mybatis新手常見問題
問題一:
### Error building SqlSession.
### The error may exist in com/yang/dao/UserMapper.xml
### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 5; columnNumber: 14; 1 字節(jié)的 UTF-8 序列的字節(jié) 1 無效。
MyBatis配置文件之后出現(xiàn)的錯(cuò)誤,而且出現(xiàn)了一長串,通過名字和行數(shù)定位了問題,原來pom.xml不能有中文,所以去掉所有中文注釋行
問題二:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.yang.dao.UserMapper.getUserList
Invalid bound statement (not found)這個(gè)問題的實(shí)質(zhì)就是 mapper接口和mapper.xml沒有映射起來,而有一個(gè)小細(xì)節(jié)是:這里的mapper的xml配置文件里面的id不能隨便寫,mapper接口的函數(shù)名稱和mapper.xml里面的標(biāo)簽id必須是一致的,我以為隨便哪個(gè)都行結(jié)果大錯(cuò)特錯(cuò),結(jié)果表示沒找到。
類似問題解決方案:https://www.jianshu.com/p/8858d3f997e2
問題三,xml文件報(bào)錯(cuò)
Cause: java.sql.SQLSyntaxErrorException: Unknown column '嫻?' in 'field list'
當(dāng)你mybatis用$-美元字符時(shí),必須要給非整型的(尤其是中文)加上引號,當(dāng)你使用#井號時(shí),可以不用在意
所以盡量多用#號,可以防注入等多個(gè)優(yōu)點(diǎn)(詳情可以看crud部分的介紹)
匯總小問題:
- 不要匹配錯(cuò)標(biāo)簽,id對應(yīng)的是dao里面的類!
- resource綁定mapper,需要使用路徑
- 程序配置文件必須符合規(guī)范–比如不能有中文
- NullPointException,沒有注冊到資源
- 輸出的xml文件中存在中文亂碼問題
- maven資源沒有導(dǎo)出問題
總結(jié)
基礎(chǔ)配置
- pom.xml
- 配置一些依賴包的導(dǎo)入
功能部分需要三個(gè)部分
-
pojo實(shí)體類
- 對象的基本組成以及類型
-
dao里面的xMapper接口(映射到xml文件)
- 各種獲取數(shù)據(jù)的放大
-
xml文件
- 配置各個(gè)映射,其中包括了各個(gè)方法
資源部分需要兩個(gè)部分
-
x.properties文件
- 包括了數(shù)據(jù)庫基礎(chǔ)配置文件日志配置文件(非必須)
-
mybatis-config.xml文件
-
配置環(huán)境(數(shù)據(jù)庫的資源導(dǎo)入)
<properties resource="db.properties" />
-
日志
<settings> <setting name="logImpl" value="STDOUT_LOGGING"></setting> </settings>
-
映射(包的映射,避免以后在功能部分導(dǎo)入包的時(shí)候還用完整的路徑)文章來源:http://www.zghlxwxcb.cn/news/detail-426216.html
-
一共3種方法—typeAlias(類型別名,這個(gè)可以用注解),package(這個(gè)),class文章來源地址http://www.zghlxwxcb.cn/news/detail-426216.html
<typeAliases> <typeAlias type="com.yang.pojo.User" alias="User"/> <package name="com.yang.pojo"/> </typeAliases>
-
到了這里,關(guān)于Mybatis筆記分享【狂神說java】的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!