參考:https://blog.csdn.net/ddddeng_/article/details/106927021
MyBatis
1、簡介
1.1 什么是Mybatis
MyBatis 是一款優秀的持久層框架;它支持自定義 SQL、存儲過程以及高級映射。MyBatis 免除了幾乎所有的 JDBC 代碼以及設置參數和獲取結果集的工作。
MyBatis 可以通過簡單的 XML 或注解來配置和映射原始類型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 對象)為數據庫中的記錄。
1.2 持久化
持久化就是將程序的數據在持久狀態和瞬時狀態轉化的過程。
內存:斷電即失。數據庫(Jdbc),io文件持久化。
為什么要持久化?
有一些對象,不能讓他丟掉。內存太貴
1.3 持久層
Dao層、Service層、Controller層
完成持久化工作的代碼塊
層界限十分明顯
1.4 為什么需要MyBatis
幫助程序員將數據存入到數據庫中,方便,傳統的JDBC代碼太復雜了,簡化,框架,自動化,不用MyBatis也可以,技術沒有高低之分
優點:
簡單易學,靈活
sql和代碼的分離,提高了可維護性。
提供映射標簽,支持對象與數據庫的orm字段關系映射
提供對象關系映射標簽,支持對象關系組建維護
提供xml標簽,支持編寫動態sql
2、第一個Mybatis程序
思路:搭建環境 --> 導入MyBatis --> 編寫代碼 --> 測試
2.1 搭建環境
新建項目
創建一個普通的maven項目
刪除src目錄 (就可以把此工程當做父工程了,然后創建子工程)
導入maven依賴
<!--導入依賴-->
<dependencies> <!--mysqlq驅動--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.12</version> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.4</version> </dependency> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
一般情況下,我們用到的資源文件(各種xml,properites,xsd文件等)都放在src/main/resources下面,利用maven打包時,maven能把這些資源文件打包到相應的jar或者war里。
有時候,比如mybatis的mapper.xml文件,我們習慣把它和Mapper.java放一起,都在src/main/java下面,這樣利用maven打包時,就需要修改pom.xml文件,來把mapper.xml文件一起打包進jar或者war里了,否則,這些文件不會被打包的。(maven認為src/main/java只是java的源代碼路徑)。
添加build
<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> <ild>
創建一個Module
2.2 創建一個模塊(可能會報中文的錯誤,把utf-8改為utf8)
編寫mybatis的核心配置文件(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核心配置文件--> <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?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> </configuration>
編寫mybatis工具類
//sqlSessionFactory --> sqlSession public class MybatisUtils { static SqlSessionFactory sqlSessionFactory = null; static { try { //使用Mybatis第一步 :獲取sqlSessionFactory對象 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } //既然有了 SqlSessionFactory,顧名思義,我們可以從中獲得 SqlSession 的實例. // SqlSession 提供了在數據庫執行 SQL 命令所需的所有方法。 public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); } }
2.3 編寫代碼
實體類
Dao接口
public interface UserDao { public List<User> getUserList(); }
接口實現類 (由原來的UserDaoImpl轉變為一個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"> <!--namespace=綁定一個指定的Dao/Mapper接口--> <mapper namespace="com.kuang.dao.UserDao"> <select id="getUserList" resultType="com.kuang.pojo.User"> select * from USER </select> </mapper>
編寫實體類
package com.bupt.pojo; import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor public class User { private int id; private String username; }
測試

import com.bupt.dao.UserDao; import com.bupt.pojo.User; import com.bupt.utils.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.HashMap; import java.util.List; public class test { @Test public void test01(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); User userById = mapper.getUserById(1); System.out.println(userById); sqlSession.close(); } //增刪改必須提交事務 @Test public void testInsert(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); int i = mapper.addUser(new User(2, "梨花")); if(i > 0){ System.out.println("插入成功"); } sqlSession.commit(); sqlSession.close(); } @Test public void updateUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); mapper.updateUser(new User(2,"劉雷")); sqlSession.commit(); sqlSession.close(); } @Test public void testDelete(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); int i = mapper.deleteUser(30); sqlSession.commit(); sqlSession.close(); } //實現模糊查詢 @Test public void testLike(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); List<User> userLike = mapper.getUserLike("%張%"); for (User user:userLike){ System.out.println(user); } sqlSession.close(); } @Test public void testLike1(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); List<User> zhang = mapper.getUserLike1("張"); for (User user:zhang){ System.out.println(user); } sqlSession.close(); } @Test public void testMap(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserDao mapper = sqlSession.getMapper(UserDao.class); HashMap<String, Object> map = new HashMap<>(); map.put("id",4); map.put("username","王虎"); map.put("birthday","2021-03-27"); map.put("sex",1); map.put("address","北京"); int i = mapper.insertUser(map); sqlSession.commit(); sqlSession.close(); } }
注意點:
org.apache.ibatis.binding.BindingException: Type interface com.kuang.dao.UserDao is not known to the MapperRegistry.
MapperRegistry是什么?
核心配置文件中注冊mappers
junit測試

@Test public void test(){ //1.獲取SqlSession對象 SqlSession sqlSession = MybatisUtils.getSqlSession(); //2.執行SQL // 方式一:getMapper UserDao userDao = sqlSession.getMapper(UserDao.class); List<User> userList = userDao.getUserList(); for (User user : userList) { System.out.println(user); } //關閉sqlSession sqlSession.close(); }
可能會遇到的問題:
- 配置文件沒有注冊
- 綁定接口錯誤
- 方法名不對
- 返回類型不對
- Maven導出資源問題
3、CURD
1. namespace
namespace中的包名要和Dao/Mapper接口的包名一致
2. select
選擇,查詢語句;
id:就是對應的namespace中的方法名;
resultType : Sql語句執行的返回值;
parameterType : 參數類型;
編寫接口
public interface UserMapper { //查詢所有用戶 public List<User> getUserList(); //插入用戶 public void addUser(User user); }
編寫對應的mapper中的sql語句
<insert id="addUser" parameterType="com.kuang.pojo.User">
insert into user (id,name,password) values (#{id}, #{name}, #{password})
</insert>
測試
@Test public void test2() { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = new User(3,"黑子","666"); mapper.addUser(user); //增刪改一定要提交事務 sqlSession.commit(); //關閉sqlSession sqlSession.close(); }
注意:增刪改查一定要提交事務:
sqlSession.commit();
增刪改查全部流程實現
配置依賴和讓資源文件能不導出

<dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.4</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.15</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> </dependency> </dependencies> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> <include>**/*.properties</include> </includes> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.xml</include> <include>**/*.properties</include> </includes> </resource> </resources> </build>
db.properties
driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/student?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC username=root password=root
mybatis-config.xml進行核心配置
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE configuration 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5 <!--configuration核心配置文件--> 6 <configuration> 7 <properties resource="db.properties"/> 8 <environments default="development"> 9 <environment id="development"> 10 <transactionManager type="JDBC"/> 11 <dataSource type="POOLED"> 12 <property name="driver" value="${driver}"/> 13 <property name="url" value="${url}"/> 14 <property name="username" value="${username}"/> 15 <property name="password" value="${password}"/> 16 </dataSource> 17 </environment> 18 </environments> 19 <mappers> 20 <mapper resource="com/bupt/dao/UserDaoMapper.xml"></mapper> 21 </mappers> 22 </configuration>
配置類MybatisUtils 獲取sqlsession

1 package com.bupt.utils; 2 3 import org.apache.ibatis.io.Resources; 4 import org.apache.ibatis.session.SqlSession; 5 import org.apache.ibatis.session.SqlSessionFactory; 6 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 7 8 import java.io.IOException; 9 import java.io.InputStream; 10 11 12 public class MybatisUtils { 13 static SqlSessionFactory factory = null; 14 static { 15 String resource = "mybatis-config.xml"; 16 try { 17 InputStream resourceAsStream = Resources.getResourceAsStream(resource); 18 factory = new SqlSessionFactoryBuilder().build(resourceAsStream); 19 20 } catch (IOException e) { 21 e.printStackTrace(); 22 } 23 } 24 public static SqlSession getSqlSession(){ 25 return factory.openSession(); 26 } 27 }
實體類(默認和數據庫對應)

1 package com.bupt.pojo; 2 3 import lombok.AllArgsConstructor; 4 import lombok.Data; 5 6 @Data 7 @AllArgsConstructor 8 public class User { 9 private int id; 10 private String username; 11 12 }
增刪改查的接口UserDao

1 package com.bupt.dao; 2 3 import com.bupt.pojo.User; 4 5 import java.util.List; 6 import java.util.Map; 7 8 public interface UserDao { 9 10 //查詢 11 User getUserById(int id);//查詢 12 13 //insert一個用戶 14 int addUser(User user); 15 16 //更新一個用戶 17 int updateUser(User user); 18 19 //刪除 20 int deleteUser(int id); 21 22 int insertUser(Map<String,Object> map); 23 24 //模糊查詢 25 List<User> getUserLike(String name); 26 List<User> getUserLike1(String name); 27 }
增刪改查的具體實現UserDaoMapper.xml

1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="com.bupt.dao.UserDao"> 6 7 <select id="getUserById" resultType="com.bupt.pojo.User" parameterType="int"> 8 select * from user where id = #{id} 9 </select> 10 11 <!-- 對象中的屬性可以直接取出來--> 12 <insert id="addUser" parameterType="com.bupt.pojo.User" > 13 insert into user (id, username) values(#{id},#{username}); 14 </insert> 15 16 <update id="updateUser" parameterType="com.bupt.pojo.User"> 17 update user set username=#{username} where id=#{id}; 18 </update> 19 20 <delete id="deleteUser" parameterType="int"> 21 delete from user where id=#{id}; 22 </delete> 23 24 <select id="getUserLike" parameterType="String" resultType="com.bupt.pojo.User"> 25 select * from user where username like #{name} 26 </select> 27 28 <select id="getUserLike1" parameterType="String" resultType="com.bupt.pojo.User"> 29 select * from user where username like "%"#{name}"%" 30 </select> 31 32 <insert id="insertUser" parameterType="map" > 33 insert into user (id,username,birthday,sex,address) values (#{id},#{username},#{birthday},#{sex},#{address}); 34 </insert> 35 36 </mapper>
別忘了在mybatis配置文件注冊Mapper
<mappers> <mapper resource="com/bupt/dao/UserDaoMapper.xml"></mapper> </mappers>
進行測試

1 import com.bupt.dao.UserDao; 2 import com.bupt.pojo.User; 3 import com.bupt.utils.MybatisUtils; 4 import org.apache.ibatis.session.SqlSession; 5 import org.junit.Test; 6 7 import java.util.HashMap; 8 import java.util.List; 9 10 public class test { 11 @Test 12 public void test01(){ 13 SqlSession sqlSession = MybatisUtils.getSqlSession(); 14 UserDao mapper = sqlSession.getMapper(UserDao.class); 15 User userById = mapper.getUserById(1); 16 System.out.println(userById); 17 sqlSession.close(); 18 } 19 20 //增刪改必須提交事務 21 @Test 22 public void testInsert(){ 23 SqlSession sqlSession = MybatisUtils.getSqlSession(); 24 UserDao mapper = sqlSession.getMapper(UserDao.class); 25 int i = mapper.addUser(new User(2, "梨花")); 26 if(i > 0){ 27 System.out.println("插入成功"); 28 } 29 sqlSession.commit(); 30 sqlSession.close(); 31 } 32 33 @Test 34 public void updateUser(){ 35 SqlSession sqlSession = MybatisUtils.getSqlSession(); 36 UserDao mapper = sqlSession.getMapper(UserDao.class); 37 mapper.updateUser(new User(2,"劉雷")); 38 sqlSession.commit(); 39 sqlSession.close(); 40 } 41 42 @Test 43 public void testDelete(){ 44 SqlSession sqlSession = MybatisUtils.getSqlSession(); 45 UserDao mapper = sqlSession.getMapper(UserDao.class); 46 int i = mapper.deleteUser(30); 47 sqlSession.commit(); 48 sqlSession.close(); 49 } 50 //實現模糊查詢 51 @Test 52 public void testLike(){ 53 SqlSession sqlSession = MybatisUtils.getSqlSession(); 54 UserDao mapper = sqlSession.getMapper(UserDao.class); 55 List<User> userLike = mapper.getUserLike("%張%"); 56 for (User user:userLike){ 57 System.out.println(user); 58 } 59 sqlSession.close(); 60 } 61 62 @Test 63 public void testLike1(){ 64 SqlSession sqlSession = MybatisUtils.getSqlSession(); 65 UserDao mapper = sqlSession.getMapper(UserDao.class); 66 List<User> zhang = mapper.getUserLike1("張"); 67 for (User user:zhang){ 68 System.out.println(user); 69 } 70 sqlSession.close(); 71 } 72 73 @Test 74 public void testMap(){ 75 SqlSession sqlSession = MybatisUtils.getSqlSession(); 76 UserDao mapper = sqlSession.getMapper(UserDao.class); 77 HashMap<String, Object> map = new HashMap<>(); 78 map.put("id",4); 79 map.put("username","王虎"); 80 map.put("birthday","2021-03-27"); 81 map.put("sex",1); 82 map.put("address","北京"); 83 int i = mapper.insertUser(map); 84 sqlSession.commit(); 85 sqlSession.close(); 86 } 87 }
6. 萬能Map
假設,我們的實體類,或者數據庫中的表,字段或者參數過多,我們應該考慮使用Map!
UserMapper接口
//用萬能Map插入用戶
public void addUser2(Map<String,Object> map);
UserMapper.xml
<!--對象中的屬性可以直接取出來 傳遞map的key-->
<insert id="addUser2" parameterType="map">
insert into user (id,name,password) values (#{userid},#{username},#{userpassword})
</insert>
測試

1 @Test 2 public void test3(){ 3 SqlSession sqlSession = MybatisUtils.getSqlSession(); 4 UserMapper mapper = sqlSession.getMapper(UserMapper.class); 5 HashMap<String, Object> map = new HashMap<String, Object>(); 6 map.put("userid",4); 7 map.put("username","王虎"); 8 map.put("userpassword",789); 9 mapper.addUser2(map); 10 //提交事務 11 sqlSession.commit(); 12 //關閉資源 13 sqlSession.close(); 14 }
- Map傳遞參數,直接在sql中取出key即可! 【parameter=“map”】
- 對象傳遞參數,直接在sql中取出對象的屬性即可! 【parameter=“Object”】
- 只有一個基本類型參數的情況下,可以直接在sql中取到
- 多個參數用Map , 或者注解!
7. 模糊查詢
模糊查詢這么寫?
Java代碼執行的時候,傳遞通配符% %
<select id="getUserLike1" parameterType="String" resultType="com.bupt.pojo.User">
select * from user where username like #{name}
</select>
1 List<User> userList = mapper.getUserLike("%李%");
在sql拼接中使用通配符
1 <select id="getUserList2" resultType="com.bupt.pojo.User"> 2 select * from user where name like "%"#{name}"%" 3 </select>
目前程序的框架為
pom.xml

1 <?xml version="1.0" encoding="UTF8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelVersion>4.0.0</modelVersion> 6 7 <groupId>org.example</groupId> 8 <artifactId>Mybatis</artifactId> 9 <packaging>pom</packaging> 10 <version>1.0-SNAPSHOT</version> 11 <modules> 12 <module>mybatis-1-crud</module> 13 </modules> 14 <build> 15 <resources> 16 <resource> 17 <directory>src/main/java</directory> 18 <includes> 19 <include>**/*.properties</include> 20 <include>**/*.xml</include> 21 </includes> 22 <filtering>true</filtering> 23 </resource> 24 </resources> 25 </build> 26 <properties> 27 <maven.compiler.source>8</maven.compiler.source> 28 <maven.compiler.target>8</maven.compiler.target> 29 </properties> 30 <dependencies> 31 <dependency> 32 <groupId>mysql</groupId> 33 <artifactId>mysql-connector-java</artifactId> 34 <version>5.1.48</version> 35 </dependency> 36 <dependency> 37 <groupId>org.mybatis</groupId> 38 <artifactId>mybatis</artifactId> 39 <version>3.5.4</version> 40 </dependency> 41 <!--junit--> 42 <dependency> 43 <groupId>junit</groupId> 44 <artifactId>junit</artifactId> 45 <version>4.12</version> 46 <scope>test</scope> 47 </dependency> 48 49 </dependencies> 50 51 </project>
mybatis-config.xml

<?xml version="1.0" encoding="UTF8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <!--configuration核心配置文件--> <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/myschool?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/bupt/dao/UserMapper.xml"/> </mappers> </configuration>
實體類User

package com.bupt.pojo; import org.apache.ibatis.session.SqlSessionFactory; import java.util.Objects; public class User { private int id; private String name; private String pwd; public int getId() { return id; } public String getName() { return name; } public String getPwd() { return 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 User(int id, String name, String pwd) { this.id = id; this.name = name; this.pwd = pwd; } public User() { } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", pwd='" + pwd + '\'' + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return id == user.id && Objects.equals(name, user.name) && Objects.equals(pwd, user.pwd); } @Override public int hashCode() { return Objects.hash(id, name, pwd); } }
UserDao

package com.bupt.dao; import com.bupt.pojo.User; import java.util.HashMap; import java.util.List; import java.util.Map; public interface UserDao { //查詢接口 List<User> getUserList(); User getUserById(int id); //插入接口 public void addUser(User user); //更新一個用戶 public void updateUser(User user); //刪除一個用戶 public void deleteUser(int id); //插入用戶 public void addUser2(Map<String, Object> map); //模糊查詢用戶 List<User> getUserList2(String name); }
UserMapper.xml

<?xml version="1.0" encoding="UTF8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--configuration核心配置文件--> <mapper namespace="com.bupt.dao.UserDao"> <select id="getUserList" resultType="com.bupt.pojo.User"> select * from USER; </select> <select id="getUserById" parameterType="int" resultType="com.bupt.pojo.User"> select * from USER where id=#{id}; </select> <insert id="addUser" parameterType="com.bupt.pojo.User"> insert into user (id,name,pwd) values (#{id},#{name},#{pwd}); </insert> <update id="updateUser" parameterType="com.bupt.pojo.User"> update user set name=#{name}, pwd=#{pwd} where id=#{id}; </update> <delete id="deleteUser" parameterType="int"> delete from user where id = #{id} </delete> <insert id="addUser2" parameterType="map"> insert into user(id,name) values(#{userid},#{username}) </insert> <select id="getUserList2" resultType="com.bupt.pojo.User"> select * from user where name like "%"#{name}"%" </select> </mapper>
MybatisUtils

1 package com.bupt.utils; 2 3 import org.apache.ibatis.io.Resources; 4 import org.apache.ibatis.session.SqlSession; 5 import org.apache.ibatis.session.SqlSessionFactory; 6 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 7 8 import java.io.IOException; 9 import java.io.InputStream; 10 11 public class MybatisUtils { 12 static SqlSessionFactory build = null; 13 static { 14 String resources = "mybatis-config.xml"; 15 try { 16 InputStream resourceAsStream = Resources.getResourceAsStream(resources); 17 build = new SqlSessionFactoryBuilder().build(resourceAsStream); 18 19 } catch (IOException e) { 20 e.printStackTrace(); 21 } 22 } 23 public static SqlSession getSqlSession(){ 24 return build.openSession(); 25 } 26 }
經常碰到這樣的面試題目:#{}和${}的區別是什么?
網上的答案是:#{}是預編譯處理,$ {}是字符串替換。
mybatis在處理#{}時,會將sql中的#{}替換為?號,調用PreparedStatement的set方法來賦值;
mybatis在處理 $ { } 時,就是把 ${ } 替換成變量的值。
使用 #{} 可以有效的防止SQL注入,提高系統安全性。
sql注入指的是用戶輸入 or 1=1等變量導致原sql語句邏輯發生了變化,使得可以直接進入數據庫,而使用預編譯的方法可以讓sql語句只把傳入的數據當做參數進行處理
而不會改變原有sql的邏輯,preparestatement和#{}都是把變量預編譯,防止sql注入。
SQL注入詳解 - myseries - 博客園 (cnblogs.com)
4、配置解析
1. 核心配置文件
-
mybatis-config.xml
-
Mybatis的配置文件包含了會深深影響MyBatis行為的設置和屬性信息。
1 configuration(配置) 2 properties(屬性) 3 settings(設置) 4 typeAliases(類型別名) 5 typeHandlers(類型處理器) 6 objectFactory(對象工廠) 7 plugins(插件) 8 environments(環境配置) 9 environment(環境變量) 10 transactionManager(事務管理器) 11 dataSource(數據源) 12 databaseIdProvider(數據庫廠商標識) 13 mappers(映射器)
2. 環境配置 environments
MyBatis 可以配置成適應多種環境
不過要記住:盡管可以配置多個環境,但每個 SqlSessionFactory 實例只能選擇一種環境
學會使用配置多套運行環境!
MyBatis默認的事務管理器就是JDBC ,連接池:POOLED
3. 屬性 properties
我們可以通過properties屬性來實現引用配置文件
這些屬性可以在外部進行配置,並可以進行動態替換。你既可以在典型的 Java 屬性文件中配置這些屬性,也可以在 properties 元素的子元素中設置。【db.poperties】
編寫一個配置文件
db.properties
1 driver=com.mysql.cj.jdbc.Driver 2 url=jdbc:mysql://localhost:3306/mybatis?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC 3 username=root 4 password=root
在核心配置文件中引入
<!--引用外部配置文件--> <properties resource="db.properties"> <property name="username" value="root"/> <property name="password" value="root"/> </properties>
- 可以直接引入外部文件
- 可以在其中增加一些屬性配置
- 如果兩個文件有同一個字段,優先使用外部配置文件的
類型別名 typeAliases
類型別名可為 Java 類型設置一個縮寫名字。 它僅用於 XML 配置.
意在降低冗余的全限定類名書寫。
<!--可以給實體類起別名-->
<typeAliases> <typeAlias type="com.kuang.pojo.User" alias="User"/> </typeAliases>
也可以指定一個包,每一個在包 domain.blog 中的 Java Bean,在沒有注解的情況下,會使用 Bean 的首字母小寫的非限定類名來作為它的別名。 比如 domain.blog.Author 的別名為 author,;若有注解,則別名為其注解值。見下面的例子:
<typeAliases>
<package name="com.kuang.pojo"/>
</typeAliases>
在實體類比較少的時候,使用第一種方式。
如果實體類十分多,建議用第二種掃描包的方式。
第一種可以DIY別名,第二種不行,如果非要改,需要在實體上增加注解。
@Alias("author") public class Author { ... }
5. 設置 Settings
這是 MyBatis 中極為重要的調整設置,它們會改變 MyBatis 的運行時行為。
6. 其他配置
typeHandlers(類型處理器)
objectFactory(對象工廠)
plugins 插件
mybatis-generator-core
mybatis-plus
通用mapper
7. 映射器 mappers
MapperRegistry:注冊綁定我們的Mapper文件;
方式一:【推薦使用】
<!--每一個Mapper.xml都需要在MyBatis核心配置文件中注冊--> <mappers> <mapper resource="com/kuang/dao/UserMapper.xml"/> </mappers>
方式二:使用class文件綁定注冊
<!--每一個Mapper.xml都需要在MyBatis核心配置文件中注冊-->
<mappers>
<mapper class="com.kuang.dao.UserMapper"/>
</mappers>
注意點:
接口和他的Mapper配置文件必須同名
接口和他的Mapper配置文件必須在同一個包下
方式三:使用包掃描進行注入
<mappers>
<package name="com.kuang.dao"/>
</mappers>
8. 作用域和生命周期
聲明周期和作用域是至關重要的,因為錯誤的使用會導致非常嚴重的並發問題。
SqlSessionFactoryBuilder:
一旦創建了SqlSessionFactory,就不再需要它了
局部變量
SqlSessionFactory:
說白了就可以想象為:數據庫連接池
SqlSessionFactory一旦被創建就應該在應用的運行期間一直存在,沒有任何理由丟棄它或重新創建一個實例。
因此SqlSessionFactory的最佳作用域是應用作用域(ApplocationContext)。
最簡單的就是使用單例模式或靜態單例模式。
SqlSession:
連接到連接池的一個請求
SqlSession 的實例不是線程安全的,因此是不能被共享的,所以它的最佳的作用域是請求或方法作用域。
用完之后需要趕緊關閉,否則資源被占用!
8、使用注解開發
8.1 面向接口開發
三個面向區別
面向對象是指,我們考慮問題時,以對象為單位,考慮它的屬性和方法;
面向過程是指,我們考慮問題時,以一個具體的流程(事務過程)為單位,考慮它的實現;
接口設計與非接口設計是針對復用技術而言的,與面向對象(過程)不是一個問題,更多的體現就是對系統整體的架構;
8.2 使用注解開發
注解在接口上實現
@Select("select * from user")
List<User> getUsers();
需要在核心配置文件中綁定接口
<mappers>
<mapper class="com.kuang.dao.UserMapper"/>
</mappers>
增刪改查
1 package com.bupt.dao; 2 3 import com.bupt.pojo.User; 4 import org.apache.ibatis.annotations.*; 5 6 import java.util.List; 7 import java.util.Map; 8 9 public interface UserDao { 10 11 User getUserById(int id); 12 List<User> getUserAll(Map<String,Integer> map); 13 14 @Select("select * from user") 15 List<User> getUsers(); 16 17 @Delete("delete from user where id=#{uid}") 18 int deleteUser(@Param("uid") int id); 19 20 @Insert("insert into user(id,username) values(#{id},#{username})") 21 int insertUser(User user); 22 23 @Update("update user set username=#{username} where id=#{id}") 24 int update(User user); 25 26 }
對於增刪改需要把opensession的參數設置為true,這樣就等價於commit操作了,否則無法commit,及時寫了commit,
public static SqlSession getSqlSession(){ SqlSession sqlSession = build.openSession(true); return sqlSession; }

1 import com.bupt.dao.UserDao; 2 import com.bupt.pojo.User; 3 import com.bupt.utils.MybatisUtils; 4 import javafx.geometry.VPos; 5 import org.apache.ibatis.session.SqlSession; 6 import org.junit.Test; 7 8 import java.util.HashMap; 9 import java.util.List; 10 import java.util.Map; 11 import java.util.logging.Logger; 12 13 public class TestGetUserById { 14 15 @Test 16 public void test01(){ 17 Logger logger = Logger.getLogger(String.valueOf(UserDao.class)); 18 logger.info("info: 測試log4j"); 19 SqlSession sqlSession = MybatisUtils.getSqlSession(); 20 UserDao mapper = sqlSession.getMapper(UserDao.class); 21 User userById = mapper.getUserById(1); 22 System.out.println(userById); 23 sqlSession.close(); 24 } 25 26 @Test 27 public void test02(){ 28 SqlSession sqlSession = MybatisUtils.getSqlSession(); 29 UserDao mapper = sqlSession.getMapper(UserDao.class); 30 HashMap<String, Integer> stringHashMap = new HashMap<String, Integer>(); 31 stringHashMap.put("startIndex",1); 32 stringHashMap.put("pagesize",2); 33 List<User> userAll = mapper.getUserAll(stringHashMap); 34 for (User user:userAll){ 35 System.out.println(user); 36 } 37 sqlSession.close(); 38 } 39 40 @Test 41 public void test03(){ 42 SqlSession sqlSession = MybatisUtils.getSqlSession(); 43 UserDao mapper = sqlSession.getMapper(UserDao.class); 44 List<User> users = mapper.getUsers(); 45 for (User user:users){ 46 System.out.println(user); 47 } 48 sqlSession.close(); 49 } 50 51 @Test 52 public void test04(){ 53 SqlSession sqlSession = MybatisUtils.getSqlSession(); 54 UserDao mapper = sqlSession.getMapper(UserDao.class); 55 int i = mapper.deleteUser(2); 56 System.out.println(i); 57 sqlSession.close(); 58 } 59 @Test 60 public void test05(){ 61 SqlSession sqlSession = MybatisUtils.getSqlSession(); 62 UserDao mapper = sqlSession.getMapper(UserDao.class); 63 int i = mapper.insertUser(new User(3,"test")); 64 System.out.println(i); 65 sqlSession.close(); 66 } 67 68 @Test 69 public void test06(){ 70 SqlSession sqlSession = MybatisUtils.getSqlSession(); 71 UserDao mapper = sqlSession.getMapper(UserDao.class); 72 int i = mapper.update(new User(3,"test02")); 73 System.out.println(i); 74 sqlSession.close(); 75 } 76 }
測試
本質:反射機制實現
底層:動態代理
MyBatis詳細執行流程
8.3 注解CURD
//方法存在多個參數,所有的參數前面必須加上@Param("id")注解
@Delete("delete from user where id = ${uid}")
int deleteUser(@Param("uid") int id);
關於@Param( )注解
基本類型的參數或者String類型,需要加上
引用類型不需要加
如果只有一個基本類型的話,可以忽略,但是建議大家都加上
我們在SQL中引用的就是我們這里的@Param()中設定的屬性名
#{} 和 ${}
9、Lombok
Lombok項目是一個Java庫,它會自動插入編輯器和構建工具中,Lombok提供了一組有用的注釋,用來消除Java類中的大量樣板代碼。僅五個字符(@Data)就可以替換數百行代碼從而產生干凈,簡潔且易於維護的Java類。
使用步驟:
在IDEA中安裝Lombok插件
在項目中導入lombok的jar包
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.10</version> <scope>provided</scope> </dependency>
在程序上加注解
1 @Getter and @Setter 2 @FieldNameConstants 3 @ToString 4 @EqualsAndHashCode 5 @AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor 6 @Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog 7 @Data 8 @Builder 9 @SuperBuilder 10 @Singular 11 @Delegate 12 @Value 13 @Accessors 14 @Wither 15 @With 16 @SneakyThrows 17 @val
說明:
@Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String name; private String password; }
對於mybatis來說復雜的sql語句還是用配置文件來做,下面兩個點是多對一和一對多的介紹。推薦使用聯合嵌套查詢
10、多對一處理
多個學生一個老師;
數據庫表

1 CREATE TABLE `teacher` ( 2 `id` INT(10) NOT NULL, 3 `name` VARCHAR(30) DEFAULT NULL, 4 PRIMARY KEY (`id`) 5 ) ENGINE=INNODB DEFAULT CHARSET=utf8 6 7 INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老師'); 8 9 CREATE TABLE `student` ( 10 `id` INT(10) NOT NULL, 11 `name` VARCHAR(30) DEFAULT NULL, 12 `tid` INT(10) DEFAULT NULL, 13 PRIMARY KEY (`id`), 14 KEY `fktid` (`tid`), 15 CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`) 16 ) ENGINE=INNODB DEFAULT CHARSET=utf8INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1'); 17 INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小紅', '1'); 18 INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小張', '1'); 19 INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1'); 20 INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');
1. 測試環境搭建
- 導入lombok
- 新建實體類Teacher,Student
- 建立Mapper接口
- 建立Mapper.xml文件
- 在核心配置文件中綁定注冊我們的Mapper接口或者文件 【方式很多,隨心選】
- 測試查詢是否能夠成功
具體過程為
先在maven里面添加依賴

1 <dependencies> 2 <dependency> 3 <groupId>org.projectlombok</groupId> 4 <artifactId>lombok</artifactId> 5 <version>1.18.16</version> 6 </dependency> 7 <dependency> 8 <groupId>junit</groupId> 9 <artifactId>junit</artifactId> 10 <version>4.13</version> 11 <scope>test</scope> 12 </dependency> 13 <dependency> 14 <groupId>mysql</groupId> 15 <artifactId>mysql-connector-java</artifactId> 16 <version>8.0.15</version> 17 </dependency> 18 <dependency> 19 <groupId>org.mybatis</groupId> 20 <artifactId>mybatis</artifactId> 21 <version>3.5.4</version> 22 </dependency> 23 <dependency> 24 <groupId>log4j</groupId> 25 <artifactId>log4j</artifactId> 26 <version>1.2.12</version> 27 </dependency> 28 29 </dependencies>
配置文件
db.properties

1 driver=com.mysql.cj.jdbc.Driver 2 url=jdbc:mysql://localhost:3306/student?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC 3 username=root 4 password=root
log4j.properties

1 #將等級為DEBUG的日志信息輸出到console和file這兩個目的地,console和file的定義在下面的代碼 2 log4j.rootLogger=DEBUG,console,file 3 #控制台輸出的相關設置 4 log4j.appender.console = org.apache.log4j.ConsoleAppender 5 log4j.appender.console.Target = System.out 6 log4j.appender.console.Threshold=DEBUG 7 log4j.appender.console.layout = org.apache.log4j.PatternLayout 8 log4j.appender.console.layout.ConversionPattern=[%c]-%m%n 9 #文件輸出的相關設置 10 log4j.appender.file = org.apache.log4j.RollingFileAppender 11 log4j.appender.file.File=./log/rzp.log 12 log4j.appender.file.MaxFileSize=10mb 13 log4j.appender.file.Threshold=DEBUG 14 log4j.appender.file.layout=org.apache.log4j.PatternLayout 15 log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n 16 #日志輸出級別 17 log4j.logger.org.mybatis=DEBUG 18 log4j.logger.java.sql=DEBUG 19 log4j.logger.java.sql.Statement=DEBUG 20 log4j.logger.java.sql.ResultSet=DEBUG 21 log4j.logger.java.sq1.PreparedStatement=DEBUG
mybatis-config.xml

1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE configuration 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5 <!--configuration核心配置文件--> 6 <configuration> 7 <properties resource="db.properties"/> 8 <!-- <settings>--> 9 <!--<!– <setting name="logImpl" value="log4j"/>–>--> 10 <!-- </settings>--> 11 <typeAliases> 12 <typeAlias type="com.bupt.pojo.Teacher" alias="Teacher"/> 13 <typeAlias type="com.bupt.pojo.Student" alias="Student"/> 14 <typeAlias type="com.bupt.pojo.Student2" alias="Student2"/> 15 <typeAlias type="com.bupt.pojo.Teacher2" alias="Teacher2"/> 16 </typeAliases> 17 <environments default="development"> 18 <environment id="development"> 19 <transactionManager type="JDBC"></transactionManager> 20 <dataSource type="POOLED"> 21 <property name="driver" value="${driver}"/> 22 <property name="url" value="${url}"/> 23 <property name="username" value="${username}"/> 24 <property name="password" value="${password}"/> 25 </dataSource> 26 </environment> 27 </environments> 28 29 <!-- 無論使用包掃描(package)還是使用class方法要注意一下 30 (1)接口和他的Mapper配置文件必須同名 31 (2)接口和他的Mapper配置文件必須在同一個包里面 32 --> 33 <!-- <mappers>--> 34 <!-- <mapper resource="com/bupt/dao/StudentMapper.xml"/>--> 35 <!-- <mapper class="com.bupt.dao.TeacherMapper"/>--> 36 <!-- </mappers>--> 37 38 <mappers> 39 <package name="com.bupt.dao"/> 40 </mappers> 41 </configuration>
utils包下的MybatisUtils文件

1 package com.bupt.utils; 2 3 import org.apache.ibatis.io.Resources; 4 import org.apache.ibatis.session.SqlSession; 5 import org.apache.ibatis.session.SqlSessionFactory; 6 import org.apache.ibatis.session.SqlSessionFactoryBuilder; 7 8 import java.io.IOException; 9 import java.io.InputStream; 10 11 public class MybatisUtils { 12 static InputStream resourceAsStream = null; 13 static SqlSessionFactory build = null; 14 static { 15 16 try { 17 String resource = "mybatis-config.xml"; 18 resourceAsStream = Resources.getResourceAsStream(resource); 19 build = new SqlSessionFactoryBuilder().build(resourceAsStream); 20 } catch (IOException e) { 21 e.printStackTrace(); 22 } 23 } 24 25 public static SqlSession getSqlSession(){ 26 SqlSession sqlSession = build.openSession(); 27 return sqlSession; 28 } 29 }
實體類Student和Teacher

package com.bupt.pojo; import lombok.Data; @Data public class Student { private int id; private String name; private Teacher teacher; }

1 package com.bupt.pojo; 2 3 import lombok.Data; 4 5 @Data 6 public class Teacher { 7 private int id; 8 private String name; 9 }
Mapper接口和對應的配置文件
StudentMapper

1 package com.bupt.dao; 2 3 import com.bupt.pojo.Student; 4 5 import java.util.List; 6 7 public interface StudentMapper { 8 //查詢所有學生的信息,及其對應的老師的信息 9 public List<Student> getStudent(); 10 public List<Student> getStudent2(); 11 }
StudentMapper.xm;

1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="com.bupt.dao.StudentMapper"> 6 7 <select id="getStudent2" resultMap="StudentTeacher2"> 8 select s.id, s.name, t.name tname 9 from student s,teacher t 10 where s.tid = t.id 11 </select> 12 <resultMap id="StudentTeacher2" type="Student"> 13 <result property="id" column="id"/> 14 <result property="name" column="name"/> 15 <association property="teacher" javaType="Teacher" > 16 <result property="name" column="tname"/> 17 </association> 18 </resultMap> 19 20 21 <!-- 方式一 按照子查詢的方式 --> 22 <select id="getStudent" resultMap="StudentTeacher"> 23 select * from student; 24 </select> 25 26 <resultMap id="StudentTeacher" type="Student"> 27 <result property="id" column="id"/> 28 <result property="name" column="name"/> 29 <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/> 30 </resultMap> 31 32 <select id="getTeacher" resultType="Teacher"> 33 select * from teacher where id=#{tid} 34 </select> 35 </mapper>
TeacherMapper

1 package com.bupt.dao; 2 3 import com.bupt.pojo.Teacher; 4 import org.apache.ibatis.annotations.Param; 5 import org.apache.ibatis.annotations.Select; 6 7 public interface TeacherMapper { 8 9 @Select("select * from teacher where id=#{id}") 10 Teacher getTeacher(@Param("id") int id); 11 }
TeacherMapper.xml

1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="com.bupt.dao.TeacherMapper"> 6 7 </mapper>
測試

1 @Test 2 public void test01(){ 3 SqlSession sqlSession = MybatisUtils.getSqlSession(); 4 TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class); 5 Teacher teacher = mapper.getTeacher(1); 6 System.out.println(teacher); 7 sqlSession.close(); 8 } 9 10 @Test 11 public void test02(){ 12 SqlSession sqlSession = MybatisUtils.getSqlSession(); 13 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); 14 for (Student student : mapper.getStudent()) { 15 System.out.println(student); 16 } 17 sqlSession.close(); 18 } 19 20 @Test 21 public void test03(){ 22 SqlSession sqlSession = MybatisUtils.getSqlSession(); 23 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); 24 for (Student student : mapper.getStudent2()) { 25 System.out.println(student); 26 } 27 sqlSession.close(); 28 }
其中最重要的就是兩種處理方式
方式一:按照查詢嵌套處理
<!-- 思路: 1. 查詢所有的學生信息 2. 根據查詢出來的學生的tid尋找特定的老師 (子查詢) --> <select id="getStudent" resultMap="StudentTeacher"> select * from student </select> <resultMap id="StudentTeacher" type="student"> <result property="id" column="id"/> <result property="name" column="name"/> <!--復雜的屬性,我們需要單獨出來 對象:association 集合:collection--> <collection property="teacher" column="tid" javaType="teacher" select="getTeacher"/> </resultMap> <select id="getTeacher" resultType="teacher"> select * from teacher where id = #{id} </select>
方式二:按照結果嵌套處理
1 <!--按照結果進行查詢--> 2 <select id="getStudent2" resultMap="StudentTeacher2"> 3 select s.id sid , s.name sname, t.name tname 4 from student s,teacher t 5 where s.tid=t.id 6 </select> 7 <!--結果封裝,將查詢出來的列封裝到對象屬性中--> 8 <resultMap id="StudentTeacher2" type="student"> 9 <result property="id" column="sid"/> 10 <result property="name" column="sname"/> 11 <association property="teacher" javaType="teacher"> 12 <result property="name" column="tname"></result> 13 </association> 14 </resultMap>
回顧Mysql多對一查詢方式:
- 子查詢 (按照查詢嵌套)
- 聯表查詢 (按照結果嵌套)
11、一對多處理
一個老師多個學生;
對於老師而言,就是一對多的關系;
1. 環境搭建
實體類
1 @Data 2 public class Student { 3 private int id; 4 private String name; 5 private int tid; 6 }
1 @Data 2 public class Teacher { 3 private int id; 4 private String name; 5 6 //一個老師擁有多個學生 7 private List<Student> students; 8 }
2. 按照結果嵌套嵌套處理(推薦使用的查詢方式)
1 <!--按結果嵌套查詢--> 2 <select id="getTeacher" resultMap="StudentTeacher"> 3 SELECT s.id sid, s.name sname,t.name tname,t.id tid FROM student s, teacher t 4 WHERE s.tid = t.id AND tid = #{tid} 5 </select> 6 <resultMap id="StudentTeacher" type="Teacher"> 7 <result property="id" column="tid"/> 8 <result property="name" column="tname"/> 9 <!--復雜的屬性,我們需要單獨處理 對象:association 集合:collection 10 javaType=""指定屬性的類型! 11 集合中的泛型信息,我們使用ofType獲取 12 --> 13 <collection property="students" ofType="Student"> 14 <result property="id" column="sid"/> 15 <result property="name" column="sname"/> 16 <result property="tid" column="tid"/> 17 </collection> 18 </resultMap>
子查詢方式實現一對多
1 <select id="getTeacher2" resultMap="TeacherStudent2"> 2 select * from teacher where id=#{tid} 3 </select> 4 <resultMap id="TeacherStudent2" type="Teacher2"> 5 <collection property="student" javaType="ArrayList" ofType="Student2" select="getTeacherStudent2" column="id"/> 6 </resultMap> 7 <select id="getTeacherStudent2" resultType="Student2"> 8 select * 9 from student where tid = #{tid}; 10 </select>
小結
關聯 - association 【多對一】
集合 - collection 【一對多】
javaType & ofType
JavaType用來指定實體類中的類型
ofType用來指定映射到List或者集合中的pojo類型,泛型中的約束類型
注意點:
- 保證SQL的可讀性,盡量保證通俗易懂
- 注意一對多和多對一,屬性名和字段的問題
- 如果問題不好排查錯誤,可以使用日志,建議使用Log4j
面試高頻
- Mysql引擎
- InnoDB底層原理
- 索引
- 索引優化
12、動態SQL
什么是動態SQL:動態SQL就是根據不同的條件生成不同的SQL語句
所謂的動態SQL,本質上還是SQL語句,只是我們可以在SQL層面,去執行一個邏輯代碼
動態 SQL 是 MyBatis 的強大特性之一。如果你使用過 JDBC 或其它類似的框架,你應該能理解根據不同條件拼接 SQL 語句有多痛苦,例如拼接時要確保不能忘記添加必要的空格,還要注意去掉列表最后一個列名的逗號。利用動態 SQL,可以徹底擺脫這種痛苦。
搭建環境
CREATE TABLE `mybatis`.`blog` ( `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '博客id', `title` varchar(30) NOT NULL COMMENT '博客標題', `author` varchar(30) NOT NULL COMMENT '博客作者', `create_time` datetime(0) NOT NULL COMMENT '創建時間', `views` int(30) NOT NULL COMMENT '瀏覽量', PRIMARY KEY (`id`) )
創建一個基礎工程
導包
編寫配置文件
編寫實體類
1 @Data 2 public class Blog { 3 private int id; 4 private String title; 5 private String author; 6 7 private Date createTime;// 屬性名和字段名不一致 8 private int views; 9 }
BlogMapper

1 package com.bupt.dao; 2 3 import com.bupt.pojo.Blog; 4 5 import java.util.List; 6 import java.util.Map; 7 8 public interface BlogMapper { 9 10 int addBook(Blog blog); 11 12 List<Blog> queryBlogIf(Map map); 13 14 List<Blog> queryChoose(Map map); 15 16 //更新博客 17 int updateBlog(Map map); 18 }
BlogMapper.xml
通過使用動態sql可以動態的編寫sql語句,並且動態sql可以自動去除多余的and和where和,等多余的內容。
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="com.bupt.dao.BlogMapper"> 6 7 <insert id="addBook" parameterType="blog"> 8 insert into blog(id,title,author,create_time,views) values (#{id},#{title},#{author},#{createTime},#{views}); 9 </insert> 10 11 <select id="queryBlogIf" parameterType="map" resultType="blog"> 12 select * from blog 13 <where> 14 <if test="title != null"> 15 title = #{title} 16 </if> 17 <if test="author != null"> 18 and author = #{author} 19 </if> 20 </where> 21 </select> 22 23 <select id="queryChoose" parameterType="map" resultType="blog"> 24 select * from blog 25 <where> 26 <choose> 27 <when test="title != null"> 28 title = #{title} 29 </when> 30 <when test="author !=null"> 31 and author = #{author} 32 </when> 33 <otherwise> 34 and view = #{views} 35 </otherwise> 36 </choose> 37 </where> 38 </select> 39 40 <update id="updateBlog" parameterType="map"> 41 update blog 42 <set> 43 <if test="title != null"> 44 title = #{title}, 45 </if> 46 <if test="author != null"> 47 author = #{author} 48 </if> 49 </set> 50 where id = #{id} 51 </update> 52 53 54 </mapper>
SQL片段
有的時候,我們可能會將一些功能的部分抽取出來,方便服用!
使用SQL標簽抽取公共部分可
<sql id="if-title-author"> <if test="title!=null"> title = #{title} </if> <if test="author!=null"> and author = #{author} </if> </sql>
在需要使用的地方使用Include標簽引用即可
<select id="queryBlogIF" parameterType="map" resultType="blog"> select * from blog <where> <include refid="if-title-author"></include> </where> </select>
13、緩存
13.1 簡介
查詢 : 連接數據庫,耗資源 一次查詢的結果,給他暫存一個可以直接取到的地方 --> 內存:緩存
我們再次查詢的相同數據的時候,直接走緩存,不走數據庫了
什么是緩存[Cache]?
- 存在內存中的臨時數據。
- 將用戶經常查詢的數據放在緩存(內存)中,用戶去查詢數據就不用從磁盤上(關系型數據庫文件)查詢,從緩存中查詢,從而提高查詢效率,解決了高並發系統的性能問題
為什么使用緩存?
- 減少和數據庫的交互次數,減少系統開銷,提高系統效率
什么樣的數據可以使用緩存?
- 經常查詢並且不經常改變的數據 【可以使用緩存】
13.2 MyBatis緩存
- MyBatis包含一個非常強大的查詢緩存特性,它可以非常方便的定制和配置緩存,緩存可以極大的提高查詢效率。
- MyBatis系統中默認定義了兩級緩存:一級緩存和二級緩存
- 默認情況下,只有一級緩存開啟(SqlSession級別的緩存,也稱為本地緩存)
- 二級緩存需要手動開啟和配置,他是基於namespace級別的緩存。
- 為了提高可擴展性,MyBatis定義了緩存接口Cache。我們可以通過實現Cache接口來定義二級緩存。
13.3 一級緩存
一級緩存也叫本地緩存:SqlSession
與數據庫同一次會話期間查詢到的數據會放在本地緩存中
以后如果需要獲取相同的數據,直接從緩存中拿,沒必要再去查詢數據庫
測試步驟:
開啟日志
測試在一個Session中查詢兩次記錄
@Test public void test1() { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getUserById(1); System.out.println(user); System.out.println("====================================="); User user2 = mapper.getUserById(1); System.out.println(user2 == user); }
發現只進行了一次數據庫連接
緩存失效的情況:
-
查詢不同的東西
-
增刪改操作,可能會改變原來的數據,所以必定會刷新緩存
-
查詢不同的Mapper.xml
-
手動清理緩存
sqlSession.clearCache();
13.4 二級緩存
- 二級緩存也叫全局緩存,一級緩存作用域太低了,所以誕生了二級緩存
- 基於namespace級別的緩存,一個名稱空間,對應一個二級緩存
- 工作機制
- 一個會話查詢一條數據,這個數據就會被放在當前會話的一級緩存中
- 如果會話關閉了,這個會員對應的一級緩存就沒了;但是我們想要的是,會話關閉了,一級緩存中的數據被保存到二級緩存中
- 新的會話查詢信息,就可以從二級緩存中獲取內容
- 不同的mapper查詢出的數據會放在自己對應的緩存(map)中
- 一級緩存開啟(SqlSession級別的緩存,也稱為本地緩存)
二級緩存需要手動開啟和配置,他是基於namespace級別的緩存。
為了提高可擴展性,MyBatis定義了緩存接口Cache。我們可以通過實現Cache接口來定義二級緩存。
步驟:
開啟全局緩存
<!--顯示的開啟全局緩存,默認也是開啟的,所以可以不寫,但是寫上其實是起到提醒的作用-->
<setting name="cacheEnabled" value="true"/>
在Mapper.xml中使用緩存
<!--在當前Mapper.xml中使用二級緩存-->
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
-
測試
- 問題:我們需要將實體類序列化,否則就會報錯
小結:
- 只要開啟了二級緩存,在同一個Mapper下就有效
- 所有的數據都會放在一級緩存中
- 只有當前會話提交,或者關閉的時候,才會提交到二級緩存中
13.5 緩存原理
注意:
只有查詢才有緩存,根據數據是否需要緩存(修改是否頻繁選擇是否開啟)useCache=“true”
<select id="getUserById" resultType="user" useCache="true"> select * from user where id = #{id} </select>
13.6 自定義緩存-ehcache
Ehcache是一種廣泛使用的開源Java分布式緩存。主要面向通用緩存
導包
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>
在mapper中指定使用我們的ehcache緩存實現
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>