- MyBatis是一款優秀的 持久層 框架,用於簡化JDBC的開發。
- MyBatis本是 Apache的一個開源專案iBatis,2010年這個專案由apache遷移到了google code,並且改名為MyBatis 。2013年11月遷移到Github。
- 官網:https://mybatis.org/mybatis-3/zh/index.html
Mybatis入門
Mybatis會把資料庫執行的查詢結果,使用實體類封裝起來(一行記錄對應一個實體類物件)
Mybatis運算元據庫的步驟:
- 準備工作(建立springboot工程、資料庫表user、實體類User)
- 引入Mybatis的相關依賴,配置Mybatis(資料庫連線資訊)
- 編寫SQL語句(註解/XML)
匯入Mybatis依賴
<!-- 僅供參考:只貼上了pom.xml中部分內容 -->
<dependencies>
<!-- mybatis起步依賴 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.0</version>
</dependency>
<!-- mysql驅動包依賴 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- spring單元測試 (整合了junit) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
資料準備
建立使用者表user,並建立對應的實體類User。
建立user表
-- 使用者表
create table user(
id int unsigned primary key auto_increment comment 'ID',
name varchar(100) comment '姓名',
age tinyint unsigned comment '年齡',
gender tinyint unsigned comment '性別, 1:男, 2:女',
phone varchar(11) comment '手機號'
) comment '使用者表';
-- 測試資料
insert into user(id, name, age, gender, phone) VALUES (null,'白眉鷹王',55,'1','18800000000');
insert into user(id, name, age, gender, phone) VALUES (null,'金毛獅王',45,'1','18800000001');
insert into user(id, name, age, gender, phone) VALUES (null,'青翼蝠王',38,'1','18800000002');
insert into user(id, name, age, gender, phone) VALUES (null,'紫衫龍王',42,'2','18800000003');
insert into user(id, name, age, gender, phone) VALUES (null,'光明左使',37,'1','18800000004');
insert into user(id, name, age, gender, phone) VALUES (null,'光明右使',48,'1','18800000005');
public class User {
private Integer id; //id(主鍵)
private String name; //姓名
private Short age; //年齡
private Short gender; //性別
private String phone; //手機號
//省略GET, SET方法
}
配置Mybatis
application.properties:
#驅動類名稱
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#資料庫連線的url
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
#連線資料庫的使用者名稱
spring.datasource.username=root
#連線資料庫的密碼
spring.datasource.password=1234
編寫SQL語句
在建立出來的springboot工程中,在引導類所在包下,在建立一個包 mapper。在mapper包下建立一個介面 UserMapper ,這是一個持久層介面(Mybatis的持久層介面規範一般都叫 XxxMapper)。
import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface UserMapper {
//查詢所有使用者資料
@Select("select id, name, age, gender, phone from user")
public List<User> list();
}
@Mapper註解:表示是mybatis中的Mapper介面
- 程式執行時:框架會自動生成介面的實現類物件(代理物件),並給交Spring的IOC容器管理
@Select註解:代表的就是select查詢,用於書寫select查詢語句
單元測試
在建立出來的SpringBoot工程中,在src下的test目錄下,測試類在執行時,會自動透過引導類載入Spring的環境(IOC容器)。我們要測試那個bean物件,就可以直接透過@Autowired註解直接將其注入進行,然後就可以測試了。
測試類程式碼如下:
@SpringBootTest
public class MybatisQuickstartApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testList(){
List<User> userList = userMapper.list();
for (User user : userList) {
System.out.println(user);
}
}
}
執行結果:
User{id=1, name='白眉鷹王', age=55, gender=1, phone='18800000000'} User{id=2, name='金毛獅王', age=45, gender=1, phone='18800000001'} User{id=3, name='青翼蝠王', age=38, gender=1, phone='18800000002'} User{id=4, name='紫衫龍王', age=42, gender=2, phone='18800000003'} User{id=5, name='光明左使', age=37, gender=1, phone='18800000004'} User{id=6, name='光明右使', age=48, gender=1, phone='18800000005'}
資料庫連線池
如果我們想把預設的資料庫連線池切換為Druid資料庫連線池,只需要完成以下兩步操作即可:
參考官方地址:https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter
1.在pom.xml檔案中引入依賴
<dependency>
<!-- Druid連線池依賴 -->
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
2.在application.properties中引入資料庫連線配置
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://localhost:3306/mybatis
spring.datasource.druid.username=root
spring.datasource.druid.password=1234
Mybatis基礎增刪改查
刪除
@Mapper
public interface EmpMapper {
/**
* 根據id刪除資料
* @param id 使用者id
*/
@Delete("delete from emp where id = #{id}")//使用#{key}方式獲取方法中的引數值
public void delete(Integer id);
}
日誌輸入
#指定mybatis輸出日誌的位置, 輸出控制檯
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
新增
@Mapper
public interface EmpMapper {
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values (#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
public void insert(Emp emp);
}
說明:#{...} 裡面寫的名稱是物件的屬性名
預設情況下,執行插入操作時,是不會主鍵值返回的。如果我們想要拿到主鍵值,需要在Mapper介面中的方法上新增一個Options註解,並在註解中指定屬性useGeneratedKeys=true和keyProperty="實體類屬性名"
@Mapper
public interface EmpMapper {
//會自動將生成的主鍵值,賦值給emp物件的id屬性
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values (#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
public void insert(Emp emp);
}
更新
@Mapper
public interface EmpMapper {
/**
* 根據id修改員工資訊
* @param emp
*/
@Update("update emp set username=#{username}, name=#{name}, gender=#{gender}, image=#{image}, job=#{job}, entrydate=#{entrydate}, dept_id=#{deptId}, update_time=#{updateTime} where id=#{id}")
public void update(Emp emp);
}
查詢
根據ID查詢
@Mapper
public interface EmpMapper {
@Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp where id=#{id}")
public Emp getById(Integer id);
}
注意
- 實體類屬性名和資料庫表查詢返回的欄位名一致,mybatis會自動封裝。
- 如果實體類屬性名和資料庫表查詢返回的欄位名不一致,不能自動封裝
解決方案:
- 起別名
- 結果對映
- 開啟駝峰命名
起別名:在SQL語句中,對不一樣的列名起別名,別名和實體類屬性名一樣
@Select("select id, username, password, name, gender, image, job, entrydate, " +
"dept_id AS deptId, create_time AS createTime, update_time AS updateTime " +
"from emp " +
"where id=#{id}")
public Emp getById(Integer id);
手動結果對映:透過 @Results及@Result 進行手動結果對映
@Results({@Result(column = "dept_id", property = "deptId"),
@Result(column = "create_time", property = "createTime"),
@Result(column = "update_time", property = "updateTime")})
@Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp where id=#{id}")
public Emp getById(Integer id);
開啟駝峰命名(推薦):如果欄位名與屬性名符合駝峰命名規則,mybatis會自動透過駝峰命名規則對映
# 在application.properties中新增:
mybatis.configuration.map-underscore-to-camel-case=true
要使用駝峰命名前提是 實體類的屬性 與 資料庫表中的欄位名嚴格遵守駝峰命名。
條件查詢
注意事項:
方法中的形參名和SQL語句中的引數佔位符名保持一致
使用MySQL提供的字串拼接函式:concat('%' , '關鍵字' , '%')
Mybatis動態SQL
Mybatis的XML配置檔案
Mybatis的開發有兩種方式:註解,XML
在Mybatis中使用XML對映檔案方式開發,需要符合一定的規範:
- XML對映檔案的名稱與Mapper介面名稱一致,並且將XML對映檔案和Mapper介面放置在相同包下(同包同名)
- XML對映檔案的namespace屬性為Mapper介面全限定名一致
- XML對映檔案中sql語句的id與Mapper介面中的方法名一致,並保持返回型別一致。
xml對映檔案中的dtd約束,直接從mybatis官網複製即可
<?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">
<mapper namespace="">
</mapper>
配置:XML對映檔案的namespace屬性為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">
<mapper namespace="com.itheima.mapper.EmpMapper">
</mapper>
配置:XML對映檔案中sql語句的id與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">
<mapper namespace="com.itheima.mapper.EmpMapper">
<!--查詢操作-->
<select id="list" resultType="com.itheima.pojo.Emp">
select * from emp
where name like concat('%',#{name},'%')
and gender = #{gender}
and entrydate between #{begin} and #{end}
order by update_time desc
</select>
</mapper>
動態SQL-if
<if>
:用於判斷條件是否成立。使用test屬性進行條件判斷,如果條件為true,則拼接SQL。
<if test="條件表示式">
要拼接的sql語句
</if>
示例:把SQL語句改造為動態SQL方式
- 原有的SQL語句
<select id="list" resultType="com.itheima.pojo.Emp">
select * from emp
where name like concat('%',#{name},'%')
and gender = #{gender}
and entrydate between #{begin} and #{end}
order by update_time desc
</select>
- 動態SQL語句
<select id="list" resultType="com.itheima.pojo.Emp">
select * from emp
<where>
<if test="name != null">
name like concat('%',#{name},'%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
</where>
order by update_time desc
</select>
<where>
只會在子元素有內容的情況下才插入where子句,而且會自動去除子句的開頭的AND或OR<set>
:動態的在SQL語句中插入set關鍵字,並會刪掉額外的逗號。(用於update語句中)
動態SQL-foreach
SQL語句
delete from emp where id in (1,2,3);
Mapper介面:
@Mapper
public interface EmpMapper {
//批次刪除
public void deleteByIds(List<Integer> ids);
}
XML對映檔案:
- 使用
<foreach>
遍歷deleteByIds方法中傳遞的引數ids集合
<foreach collection="集合名稱" item="集合遍歷出來的元素/項" separator="每一次遍歷使用的分隔符"
open="遍歷開始前拼接的片段" close="遍歷結束後拼接的片段">
</foreach>
<?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">
<mapper namespace="com.itheima.mapper.EmpMapper">
<!--刪除操作-->
<delete id="deleteByIds">
delete from emp where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
</mapper>
動態SQL-sql&include(使用範圍有限,不常用)
問題分析:
- 在xml對映檔案中配置的SQL,有時可能會存在很多重複的片段,此時就會存在很多冗餘的程式碼
我們可以對重複的程式碼片段進行抽取,將其透過<sql>
標籤封裝到一個SQL片段,然後再透過<include>
標籤進行引用。
-
<sql>
:定義可重用的SQL片段 -
<include>
:透過屬性refid,指定包含的SQL片段
SQL片段: 抽取重複的程式碼
<sql id="commonSelect">
select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp
</sql>
然後透過<include>
標籤在原來抽取的地方進行引用。操作如下:
<select id="list" resultType="com.itheima.pojo.Emp">
<include refid="commonSelect"/>
<where>
<if test="name != null">
name like concat('%',#{name},'%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
</where>
order by update_time desc
</select>