MyBatis是一個優秀的持久化框架,用于簡化JDBC的開發。
持久層就是持久化訪問的層,就是數據訪問層(Dao),用于訪問數據庫的。
MyBatis使用的準備工作
創建項目,導入mybatis的啟動依賴,mysql的驅動包
在pom文件中生成依賴
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.4</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency>
首先我們準備一下數據庫的數據
?
?創建user_info表
DROP DATABASE IF EXISTS mybatis_test;CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;
USE mybatis_test;DROP TABLE IF EXISTS user_info;CREATE TABLE `user_info` (`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,`username` VARCHAR ( 127 ) NOT NULL,`password` VARCHAR ( 127 ) NOT NULL,`age` TINYINT ( 4 ) NOT NULL,`gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1
',`phone` VARCHAR ( 15 ) DEFAULT NULL,`delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0',`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now(),PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )VALUES ( 'admin', 'admin', 18, 1, '18612340001' );INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );
配置數據庫的連接(.yml文件中的配置)
?
創建數據庫表中對應的實體類
@Data
public class UserInfo {private Integer id;private String username;private String password;private Integer age;private Integer gender;private String phone;private Integer deleteFlag;private Date createTime;private Date updateTime;
}
?注:數據庫中字段全部都使用小寫,單詞之間用_來連接,Java中的屬性使用小駝峰的方式
?注:由于引入了lombok依賴,所以直接使用@Date注解,不需要再去寫Getter和Setter方法
?
創建在持久層的接口,在MyBatis中持久層中的接口一般使用 xxxMapper 的命名方法
我們創建了UserInfoMapper接口
注:@Mapper注解就是表明該接口是MyBatis中的Mapper接口
單元測試
在創建出來的SpringBoot?程中,在src下的test?錄下,已經?動幫我們創建好了測試類,我們可以 直接使?這個測試類來進?測試
單元測試是開發人員進行的測試,與測試人員無關。
?
進行測試的方法
生成測試類的方法
?找到你需要生成測試類的Mapper接口的方法上,右鍵generate,點擊Test
在你需要測試的方法上打 √ ,然后點ok就會自動生成了
MyBatis中的基礎操作(注解)
打印日志
只需要在配置文件中配置即可
就可以直接看到sql的執行過程,參數傳遞,執行結果。
參數的傳遞
查詢對象的方式(select)
id為固定值的時候
@Select("select * from user_info where id=3")List<UserInfo> selectAllById();
@Testvoid selectAllId() {System.out.println(userInfoMapper.selectAllById());}
?
id為動態的數值
使用#{}的方式獲取方法中的參數
@Select("select * from user_info where id=#{id}")UserInfo selectAllById3(Integer id);
@Testvoid selectAllById3() {System.out.println(userInfoMapper.selectAllById3(1));}
?
?
傳遞多個參數?
@Select("select * from user_info where username=#{username} and password=#{password}")UserInfo selectAllByUserNameAndPassWord(String username,String password);
@Testvoid selectAllByUserNameAndPassWord() {System.out.println(userInfoMapper.selectAllByUserNameAndPassWord("zhangsan","zhangsan"));}
?可以使用@Param注解進行參數的綁定(重命名)
@Select("select * from user_info where username=#{aa} and password=#{bb}")UserInfo selectAllByUserNameAndPassWord2(@Param("aa") String username,@Param("bb") String password);
@Testvoid selectAllByUserNameAndPassWord2() {System.out.println(userInfoMapper.selectAllByUserNameAndPassWord2("zhangsan","zhangsan"));}
?
增 (Insert)
@Insert("insert into user_info (username,password,age) values (#{username},#{password},#{age})")Integer insert(UserInfo userInfo);
@Testvoid insert() {UserInfo userInfo=new UserInfo();userInfo.setUsername("lisi");userInfo.setPassword("lisi");userInfo.setAge(1);Integer result=userInfoMapper.insert(userInfo);System.out.println("新增行數"+result);}
?
返回主鍵
獲得自增Id
//獲取自增Id@Options(useGeneratedKeys = true,keyProperty = "id")@Insert("insert into user_info (username,password,age) values (#{username},#{password},#{age})")Integer insert1(UserInfo userInfo);
@Testvoid insert1() {UserInfo userInfo=new UserInfo();userInfo.setUsername("lisi");userInfo.setPassword("lisi");userInfo.setAge(1);Integer result=userInfoMapper.insert1(userInfo);System.out.println("新增行數"+result+"Id"+userInfo.getId());}
?
刪 (delete)
@Delete("delete from user_info where id =#{id}")Integer deleteUser(Integer id);
@Testvoid deleteUser() {userInfoMapper.deleteUser(13);}
?
?
改(update)
@Update("update user_info set delete_flag= #{deleteFlag},phone= #{phone} where id= #{id}")Integer updateUser(UserInfo userInfo);
@Testvoid updateUser() {UserInfo userInfo=new UserInfo();userInfo.setDeleteFlag(1);userInfo.setPhone("123");userInfo.setId(11);Integer result=userInfoMapper.updateUser(userInfo);System.out.println(result);}
?
查詢的需要注意的問題
當我們進行查詢的時候,我們會發現某些字段是沒有進行賦值的,只有Java對象屬性和數據庫字段?模?樣時,才會進?賦值
原因:MyBatis 在執行查詢后,會將數據庫中的字段值映射(映射 = 賦值)到 Java 實體類對象的屬性中。但是,如果 數據庫字段名和 Java 對象屬性名不一致,MyBatis 默認不會自動進行映射賦值
解決辦法:
1.起別名
@Select("select id, username,`password`, age, gender, phone, " +
"delete_flag as deleteFlag, create_time as createTime, update_time as updateTime" +
" from user_info")
?2.結果映射
@Results(id = "BaseMap", value = {@Result(column = "delete_flag", property = "deleteFlag"),@Result(column = "create_time", property = "createTime"),@Result(column = "update_time", property = "updateTime")})
@Select("select * from user_info")
3.添加駝峰命名的配置文件
設置為true
MyBatis XML配置文件?
MyBatis的開發方式一般有兩種,注解 & XML
現在我們來學習XML的開發方式
配置mybatis
Spring Boot 集成 MyBatis 時指定 Mapper XML 文件的位置,告訴 MyBatis 去哪里加載 SQL 映射文件?
添加Mapper接口
添加 .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"><mapper namespace="com.blame.springmybatis.mapper.UserInfoMapperXML"><select id="selectUserAll" resultType="com.blame.springmybatis.model.UserInfo">select * from user_info</select></mapper>
?
單元測試
@SpringBootTest
class UserInfoMapperXMLTest {@Autowiredprivate UserInfoMapperXML userInfoMapperXML;@Testvoid selectUserAll() {userInfoMapperXML.selectUserAll().stream().forEach(x-> System.out.println(x));}
}
?
XML中的增刪改查?
增(insert)
Integer insertUser(UserInfo userInfo);
<insert id="insertUser">insert into user_info (username, `password`, age) VALUES (#{username}, #{password}, #{age})</insert>
@Testvoid insertUser() {UserInfo userInfo=new UserInfo();userInfo.setUsername("xiaohei");userInfo.setPassword("123");userInfo.setAge(11);Integer result=userInfoMapperXML.insertUser(userInfo);System.out.println("增加行數"+result+"Id"+userInfo.getId());}
?
使用@Param注解進行重命名
Integer insertUser2(@Param("UserInfo") UserInfo userInfo);
<insert id="insertUser2">insert into user_Info (username, `password`, age) VALUES (#{username}, #{password}, #{age})</insert>
@Testvoid insertUser2() {UserInfo userInfo=new UserInfo();userInfo.setUsername("hei");userInfo.setPassword("15");userInfo.setAge(13);Integer result=userInfoMapperXML.insertUser(userInfo);System.out.println("增加行數"+result+"Id"+userInfo.getId());}
自增Id
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">insert into user_info (username, `password`, age, gender, phone) values(#{userInfo.username},#{userInfo.password},#{userInfo.age},#{userInfo.gender},#{userInfo.phone})</insert>
?刪(delete)
Integer deleteUser(Integer id);
<delete id="deleteUser">delete from user_info where id =#{id}</delete>
@Testvoid deleteUser() {userInfoMapperXML.deleteUser(16);}
?
?
改(update)
<update id="updateUser">update user_info set password= #{password} , age=#{age} where id= #{id}</update>
Integer updateUser(String password,Integer age,Integer id);
@Testvoid updateUser() {UserInfo userInfo=new UserInfo();Integer result=userInfoMapperXML.updateUser("123",88,9);}
查(select)?
List<UserInfo> selectUserAll();
<select id="selectUserAll" resultType="com.blame.springmybatis.model.UserInfo">select * from user_info</select>
其他查詢
聯合查詢(多表查詢)
在數據庫中導入表
DROP TABLE IF EXISTS articleinfo;
CREATE TABLE articleinfo (id INT PRIMARY KEY auto_increment,title VARCHAR ( 100 ) NOT NULL,content TEXT NOT NULL,uid INT NOT NULL,delete_flag TINYINT ( 4 ) DEFAULT 0 COMMENT,create_time DATETIME DEFAULT now(),update_time DATETIME DEFAULT now()
) DEFAULT charset 'utf8mb4';INSERT INTO articleinfo ( title, content, uid ) VALUES ( 'Java', 'Java正?', 1 );
配置對應的實體類
@Data
public class ArticleInfo {private Integer id;private String title;private String content;private Integer uid;private Integer deleteFlag;private Date createTime;private Date updateTime;private String username;private Integer age;
}
?定義接口
@Mapper
public interface ArticleInfoMapper {ArticleInfo selectArticleById(Integer id);
}
配置 .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"><mapper namespace="com.blame.springmybatis.mapper.ArticleInfoMapper"><select id="selectArticleById" resultType="com.blame.springmybatis.model.ArticleInfo">select ta.*,tb.username,tb.age from article_info ta left
join user_info tb on ta.uid = tb.id where ta.id=#{id}</select>
</mapper>
測試類
@SpringBootTest
class ArticleInfoMapperTest {@Autowiredprivate ArticleInfoMapper articleInfoMapper;@Testvoid selectArticleById() {articleInfoMapper.selectArticleById(1);}
}
?
#{ }和${ }
這是mybatis中非常重要的兩個占位符
首先我們看一下#{}
@Select("select username,`password`,age,gender,phone from user_info where id=#{id}")UserInfo queryById(Integer id);
@Testvoid queryById() {System.out.println(userInfoMapper.queryById(2));}
通過觀察我們的sql語句,我們發現我們輸入的參數 2 ,并沒有在語句后面顯示,而是用 ? ,我們把這種叫做預編譯SQL
我們再觀察一下${}
@Select("select username,`password`,age,gender,phone from user_info where id=${id}")UserInfo queryById2(Integer id);
@Testvoid queryById2() {System.out.println(userInfoMapper.queryById2(2));}
?我們可以發現參數直接是拼在SQL語句中了
我們再把參數換成String類型
@Select("select username,`password`,age,gender,phone from user_info where username=#{username}")UserInfo queryById3(String username);@Select("select username,`password`,age,gender,phone from user_info where username=${username}")UserInfo queryById4(String username);
@Testvoid queryById3() {System.out.println(userInfoMapper.queryById3("zhangsan"));}@Testvoid queryById4() {System.out.println(userInfoMapper.queryById4("zhangsan"));}
我們先來看一下#{}的測試結果
?再看一下${}的測試結果
我們發現報錯了,說SQL語法異常
這次的參數是直接拼在SQL語句的后面,沒有自動給username添加? ' '
修改后,測試成功
@Select("select username,`password`,age,gender,phone from user_info where username='${username}'")UserInfo queryById4(String username);
?
通過上面這個例子,我們可以發現#{}使用的是預編譯SQL,通過?進行占位,提前對SQL進行編譯,將參數填充到SQL語句中,#{}會根據參數類型,自動拼接引號 ' '
${}會直接進行字符的替換,一起對SQL進行編譯,如果是字符串,得加上引號' '
SQL語句的執行流程
1.語法解析????????2.SQL優化????????3.SQL編譯????????4.SQL執行?
?#{} 和${}區別
#{}的性能更高
${}會出現SQL注入的風險
SQL注入:是通過操作輸?的數據來修改事先定義好的SQL語句,以達到執?代碼對服務器進?攻擊的 ?法
SQL注入的代碼演示
@Select("select username, `password`, age, gender, phone from user_info where username= '${name}' ")List<UserInfo> queryByName(String name);
@Testvoid queryByName() {List<UserInfo> userInfos = userInfoMapper.queryByName("admin");System.out.println(userInfos);}
?測試成功
但是,如果我們參數傳為以下的情況,我們發現不僅沒有報錯,而且得到了我們表中的全部信息,這就是SQL注入
@Testvoid queryByName() {List<UserInfo> userInfos = userInfoMapper.queryByName("' or 1='1");System.out.println(userInfos);}
?
排序功能?
當我們表中數據按Id逆序進行排序,發現${}排序成功
@Select("select id, username, age, gender, phone, delete_flag, create_time,update_time " +"from user_info order by id ${sort} ")List<UserInfo> queryAllUserBySort(String sort);
@Testvoid queryAllUserBySort() {System.out.println(userInfoMapper.queryAllUserBySort("desc"));}
但我們發現#{}?沒有成功,進行了報錯。
@Select("select id, username, age, gender, phone, delete_flag, create_time,update_time " +"from user_info order by id #{sort} ")List<UserInfo> queryAllUserBySort2(String sort);
SQL語法錯誤異常?
?
可以發現,當使? #{sort} 查詢時,asc前后?動給加了引號,導致sql錯誤
like的使用
@Select("select id, username, age, gender, phone, delete_flag, create_time,
update_time " +"from user_info where username like '%#{key}%' ")List<UserInfo> queryAllUserByLike(String key);
這里 '%#{key}%'
是錯誤寫法,因為 #{}
在 MyBatis 中是 參數占位符,它不會在 SQL 字符串內部被當作字符串拼接,而是被替換成 ?
?
我們可以使用從concat()
@Select("select id, username, age, gender, phone, delete_flag, create_time,
update_time " +"from user_info where username like concat('%',#{key},'%')")List<UserInfo> queryAllUserByLike(String key);
?
數據庫連接池
預先創建好的一批數據庫連接,當應用程序要訪問數據庫時,從池中獲取連接,操作完成后再歸還,而不是每次都重新建立和關閉連接
常用的的數據連接池
HikariCP(Spring Boot默認):性能最快、輕量
Druid(阿里巴巴):功能豐富、監控強大
C3P0 :比較落后
DBCP :使用少
切換數據庫連接池?
如果我們想把默認的數據庫連接池切換為Druid數據庫連接池,只需要引?相關依賴即可?
<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-3-starter</artifactId><version>1.2.21</version></dependency>
希望能對大家有所幫助!!!!!?
?
?