一、原始JDBC開發存在的問題
package com.qf.java2107.test;
?
import org.junit.Test;
?
import java.math.BigDecimal;
import java.sql.*;
?
/*** @author ghy* @version 1.0* @date 2021-12-22**/
public class JdbcTest {
?/*** 存在的問題:* ? ? 1. 需要頻繁的手動獲取連接* ? ? 2. 需要手動封裝查詢結果集* ? ? 3. 需要手動釋放資源* ? ? 4. SQL硬編碼* ? 有自己封裝的工具類,也有DBUtils等工具類API。但是都沒有從根本上解決上面的問題*/@Testpublic void testJdbc(){
?Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;
?try {//1.反射加載驅動Class.forName("com.mysql.jdbc.Driver");
?//2.獲取數據庫連接connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/java2106_hotel", "root", "root");
?//3.編寫SQLString sql = "SELECT * FROM t_user WHERE user_id = ?";
?//4.獲取執行SQL的載體對象,預編譯SQLpreparedStatement = connection.prepareStatement(sql);//填充占位符preparedStatement.setLong(1, 3);
?//5.執行SQLresultSet = preparedStatement.executeQuery();
?//6.處理結果if (resultSet.next()) {//user_id : 結果集的列名long userId = resultSet.getLong("user_id");String username = resultSet.getString("username");BigDecimal balance = resultSet.getBigDecimal("balance");System.out.println(userId + "," + username + "," + balance );}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();} finally {
?//7.釋放資源//先開后關try {if(null != resultSet) {resultSet.close();}} catch (SQLException e) {e.printStackTrace();}try {if(null != preparedStatement) {preparedStatement.close();}} catch (SQLException e) {e.printStackTrace();}try {if(null != connection) {connection.close();}} catch (SQLException e) {e.printStackTrace();}}
?}
}
-
存在的問題
- 需要頻繁的手動獲取連接
- 需要手動封裝查詢結果集
- 需要手動釋放資源
- SQL硬編碼
二、ORM框架
1、ORM
Java對象數據庫表
| 類名 | 表名 |
| 屬性名 | 列名【字段名】 |
| 對象 | 行【記錄】 |
2、框架
-
概述:就是一個半成品軟件
-
作用
-
能夠幫我們快速有效的開發JavaEE應用
-
有自己對應用場景的完整解決方案
三、Mybatis
1、概述
-
是一款開源的、優秀的、支持定制SQL的ORM框架
-
官網:mybatis – MyBatis 3 | 簡介
MyBatis 是一款優秀的持久層框架,它支持自定義 SQL、存儲過程以及高級映射。MyBatis 免除了幾乎所有的 JDBC 代碼以及設置參數和獲取結果集的工作。MyBatis 可以通過簡單的 XML 或注解來配置和映射原始類型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 對象)為數據庫中的記錄。
2、快速入門
3.2.1 實現步驟
創建數據庫表
導入依賴
實體類
Mapper接口【Dao接口】
SQL映射文件
全局配置文件
測試
3.2.2 具體實現
CREATE TABLE `t_user` (`user_id` bigint(100) NOT NULL AUTO_INCREMENT COMMENT '主鍵',`username` varchar(20) DEFAULT NULL COMMENT '用戶名',`password` varchar(32) DEFAULT NULL COMMENT '密碼',`nick_name` varchar(20) DEFAULT NULL COMMENT '昵稱',`is_admin` tinyint(4) DEFAULT NULL COMMENT '是否管理員 0:否 1:是',`phone` varchar(11) DEFAULT NULL COMMENT '手機',`gender` tinyint(4) DEFAULT NULL COMMENT '性別 0:保密 1:男 2:女',`birth` date DEFAULT NULL COMMENT '生日',`user_status` tinyint(4) DEFAULT NULL COMMENT '狀態(是否激活) 0:否 1:是',`user_create_time` datetime DEFAULT NULL COMMENT '創建時間',`user_update_time` datetime DEFAULT NULL COMMENT '更新時間',`is_delete` tinyint(4) DEFAULT NULL COMMENT '是否刪除 0:否 1:是',`is_member` tinyint(4) DEFAULT NULL COMMENT '是否會員 0:否 1:是',`balance` decimal(20,2) DEFAULT NULL COMMENT '賬戶余額',PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COMMENT='這是一個用戶表';
?
?
insert ?into `t_user`(`user_id`,`username`,`password`,`nick_name`,`is_admin`,`phone`,`gender`,`birth`,`user_status`,`user_create_time`,`user_update_time`,`is_delete`,`is_member`,`balance`) values
(1,'aa','e10adc3949ba59abbe56e057f20f883e','666',1,'13566778899',1,'1990-07-18',0,'2021-10-15 10:56:40','2021-10-22 10:56:43',0,1,10000.00),
(2,'bb','bb','666',1,'111111',1,'1990-07-18',0,'2021-11-02 14:20:25','2021-11-03 09:25:58',0,1,1111.00),
(3,'cc','mark123','666',1,'13512341234',0,'1990-07-18',0,'2021-11-03 10:05:37','2021-11-03 10:05:37',0,1,10000.00),
(5,'dd','BB','666',1,'13512341234',0,'1990-07-18',0,'2021-11-03 10:15:00','2021-11-03 10:15:00',0,1,10000.00),
(6,'ee','CC','666',1,'13512341234',2,'1990-07-18',0,'2021-11-03 10:40:01','2021-11-03 10:40:01',0,1,10000.00),
(7,'ff','mark123','666',0,'13512341234',0,'1990-07-18',0,'2021-11-05 11:23:45','2021-11-05 11:23:45',0,1,10000.00);
<dependencies>
?<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency>
?<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.2</version></dependency>
?<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency>
?<!-- lombok : 能夠快速幫我們生成實體的getter/setter方法 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.22</version><scope>provided</scope></dependency>
?
</dependencies>
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
?private Long userId;private String username; ? //成員變量private String password;private String nickName;private Integer isAdmin;private String phone;private Integer gender;private Date birth;private Integer userStatus;private Date userCreateTime;private Date userUpdateTime;private Integer isDelete;private Integer isMember;private BigDecimal balance;
?
}
public interface IUserMapper {
?/*** 查詢所有* @return*/List<User> findAll();
?
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--mybatis代理接口開發的要求:1.mapper映射文件的namespace 寫 mapper接口的全類名2.mapper映射文件的statementId 寫 mapper接口的對應方法名3.mapper映射文件的resultType 寫 mapper接口的對應方法返回值類型。如果是集合,寫泛型4.mapper映射文件的parameterType 寫 mapper接口的對應方法形參類型。高版本mybatis可以不寫,但是不推薦-->
<mapper namespace="com.qf.java2107.mapper.IUserMapper"><select id="findAll" resultType="com.qf.java2107.pojo.User"><!-- 原生SQL -->SELECTuser_id userId,username,password,nick_name,is_admin,phone,gender,birth,user_status,user_create_time,user_update_time,is_delete,is_member,balanceFROMt_user</select>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//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.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/java2107"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments><mappers><mapper resource="com/qf/java2107/mapper/IUserMapper.xml"/></mappers>
</configuration>
/*** mapper接口代理測試,掌握**/
@Test
public void test02() {SqlSession session = null;try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
?session = sqlSessionFactory.openSession();//獲取mapper代理IUserMapper userMapper = session.getMapper(IUserMapper.class);List<User> users = userMapper.findAll();//mybatis能夠幫我們自動完成查詢結果集和實體間的映射,前提結果集列名和實體屬性名相同for (User user : users) {System.out.println(user);}} catch (IOException e) {e.printStackTrace();} finally {if(null != session) {session.close();}}
}
四、CURD操作
1、增加
/*** 增加* @param user*/
void save(User user);
Mapper映射文件<!-- void save(User user);-->
<insert id="save" parameterType="com.qf.java2107.pojo.User">INSERT INTO t_user (username,password,nick_name,is_admin,phone,gender,birth,user_status,user_create_time,user_update_time,is_delete,is_member,balance)VALUES(#{username}, #{password}, #{nickName}, #{isAdmin}, #{phone}, #{gender}, #{birth}, #{userStatus},#{userCreateTime}, #{userUpdateTime}, #{isDelete}, #{isMember}, #{balance})
</insert>
/*** 增加**/
@Test
public void test03() throws Exception {SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));SqlSession sqlSession = factory.openSession();IUserMapper userMapper = sqlSession.getMapper(IUserMapper.class);User user = new User();user.setUsername("lucy");user.setPassword("lucy123");user.setNickName("露西");user.setIsAdmin(0);user.setPhone("13566778899");user.setGender(0);user.setBirth(java.sql.Date.valueOf("2005-10-30"));user.setUserStatus(1);user.setUserCreateTime(new Date());user.setUserUpdateTime(new Date());user.setIsDelete(0);user.setIsMember(1);user.setBalance(new BigDecimal(2000));userMapper.save(user);
?//提交事務sqlSession.commit();
?if(null != sqlSession) {sqlSession.close();}
?
}
1.1 主鍵回填
-
主鍵自增
<!--void saveReturnPrimaryKey(User user);-->
<insert id="saveReturnPrimaryKey" parameterType="com.qf.java2107.pojo.User">
?<!--selectKey : 是指要執行的相關的SQLorder: selectKey中SQL的執行順序,after代表之后,before代表之前resultType : selectKey中SQL的返回值類型keyProperty : selectKey中SQL的返回值要賦值給哪個JavaBean的屬性keyColumn : selectKey中SQL的返回值對應的數據庫表的列【這個值可以不寫,會自動映射】--><selectKey order="AFTER" resultType="java.lang.Long" keyProperty="userId" keyColumn="user_id">SELECT LAST_INSERT_ID()</selectKey>INSERT INTO t_user (username,password,nick_name,is_admin,phone,gender,birth,user_status,user_create_time,user_update_time,is_delete,is_member,balance)VALUES(#{username}, #{password}, #{nickName}, #{isAdmin}, #{phone}, #{gender}, #{birth}, #{userStatus},#{userCreateTime}, #{userUpdateTime}, #{isDelete}, #{isMember}, #{balance})
</insert> <!-- void saveReturnPrimaryKey2(User user); -->
<!--useGeneratedKeys : 是否使用主鍵生成策略true:是這種方式可以獲取批量插入的主鍵值-->
<insert id="saveReturnPrimaryKey2" parameterType="com.qf.java2107.pojo.User"useGeneratedKeys="true" keyProperty="userId" keyColumn="user_id">INSERT INTO t_user(username,password,nick_name,is_admin,phone,gender,birth,user_status,user_create_time,user_update_time,is_delete,is_member,balance)VALUES(#{username}, #{password}, #{nickName}, #{isAdmin}, #{phone}, #{gender}, #{birth}, #{userStatus},#{userCreateTime}, #{userUpdateTime}, #{isDelete}, #{isMember}, #{balance})
</insert>
2、修改
<!--int update(User user);-->
<update id="update">UPDATE t_userSET PASSWORD = #{password}, nick_name = #{nickName}, user_update_time = #{userUpdateTime}WHERE user_id = #{userId}
</update>
3、刪除
<!--boolean deleteById(Long userId);-->
<delete id="deleteById" parameterType="long">DELETE FROM t_user WHERE user_id = #{userId}
</delete>
4、主鍵是字符串實現主鍵回填
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/*** @author ghy* @version 1.0* @date**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Stu {
?private String stuId;private String stuName;
?
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qf.java2107.mapper.IStuMapper">
?<!-- int saveReturnPrimaryKey(Stu stu); --><insert id="saveReturnPrimaryKey" parameterType="com.qf.java2107.pojo.Stu"><selectKey order="BEFORE" keyProperty="stuId" resultType="string" keyColumn="stu_id">SELECT REPLACE(UUID(), '-', '')</selectKey>insert into t_stu (stu_id, stu_name) values (#{stuId},#{stuName})</insert>
?
</mapper>
五、日志
1、日志體系
-
Slf4j:接口【門面】
-
Log4j
-
Logback
-
commons-logging
2、日志作用
-
沒日志:很難判斷問題來源
-
有日志:一般都可以判斷問題來源。
3、使用
<!-- 日志 -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.7</version>
</dependency>
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=ssm.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
log4j.rootLogger=debug, stdout, file
級別描述
| ALL LEVEL | 打開所有日志記錄開關;是最低等級的,用于打開所有日志記錄。 |
| DEBUG | 輸出調試信息;指出細粒度信息事件對調試應用程序是非常有幫助的。【開發使用】 |
| INFO | 輸出提示信息;消息在粗粒度級別上突出強調應用程序的運行過程。【線上使用】 |
| WARN | 輸出警告信息;表明會出現潛在錯誤的情形。 |
| ERROR | 輸出錯誤信息;指出雖然發生錯誤事件,但仍然不影響系統的繼續運行。 |
| FATAL | 輸出致命錯誤;指出每個嚴重的錯誤事件將會導致應用程序的退出。 |
| OFF LEVEL | 關閉所有日志記錄開關;是最高等級的,用于關閉所有日志記錄。 |
package com.qf.java2107.test;
?
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
?
/*** @author ghy* @version 1.0* @date 2021-12-23**/
public class LoggerTest {
?Logger logger = LoggerFactory.getLogger(LoggerTest.class);
?/*****/@Testpublic void logTest() throws Exception {logger.debug("debug---->{}", "debug level");logger.info("info--->{}---{}", "aa", "bb");logger.warn("warn----->");logger.error("error---->");}
}
?
4、常用插件
六、Mapper接口參數綁定
1、單個簡單類型參數
基本數據類型及其包裝類,String
Mapper映射文件獲取參數值時,名稱可以隨意。但是強烈建議參數名跟形參名一致
2、實體類型參數
JavaBean
Mapper映射文件獲取參數值時,使用#{},{}中寫JavaBean的屬性名
3、Map入參
Mapper映射文件獲取參數值時,使用#{},{}中寫Map中key的名稱
|
4、多個參數
mybatis會把參數封裝成一個Map,第一個參數的key為arg0【param1】,第二參數的key為arg1【param2】,以此類推。
以上方式不推薦使用,可讀性太差。
Mapper映射文件獲取參數值時,使用@Param來為Mapper接口方法指定入參的參數名,使用#{}取值
七、ORM映射
把查詢結果集跟JavaBean進行映射綁定
1、映射規則
2、不滿足映射規則
-
如果滿足駝峰
<!-- User findByIdMapping1(Long userId); -->
<select id="findByIdMapping1" parameterType="java.lang.Long" resultType="com.qf.java2107.pojo.User">SELECTuser_id userId,username,password,nick_name nickName,is_admin isAdmin,phone,gender,birth,user_status userStatus,user_create_time userCreateTime,user_update_time userUpdateTime,is_delete isDelete,is_member isMember,balanceFROMt_userWHERE user_id = #{userId}
</select> <settings><!-- 開啟駝峰映射,編寫的SQL就不用使用別名了 --><setting name="mapUnderscoreToCamelCase" value="true"/>
</settings> <!-- User findByIdMapping2(Long userId); -->
<select id="findByIdMapping2" parameterType="java.lang.Long" resultType="com.qf.java2107.pojo.User">SELECTuser_id,username,password,nick_name,is_admin,phone,gender,birth,user_status,user_create_time,user_update_time,is_delete,is_member,balanceFROMt_userWHERE user_id = #{userId}
</select>
3、ResultMap
<!--resultMap: 自定義結果集id : resultMap的名稱,是一個唯一標識,用于被select的resultMap屬性所引用type : 查詢的結果集要映射到的實體類型-->
<resultMap id="myResultMap" type="com.qf.java2107.pojo.User"><!--id : 映射主鍵列,只是一個標識作用,也可以用resultcolumn : 查詢的結果集的列名property : JavaBean的屬性名--><id column="uid" property="userId"/><!-- result : 映射普通列 --><result column="username" property="username"/><result column="password" property="password"/><result column="name" property="nickName"/><result column="is_admin" property="isAdmin"/><result column="phone" property="phone"/><result column="sex" property="gender"/><result column="birth" property="birth"/><result column="user_status" property="userStatus"/><result column="ctime" property="userCreateTime"/><result column="user_update_time" property="userUpdateTime"/><result column="is_delete" property="isDelete"/><result column="is_member" property="isMember"/><result column="balance" property="balance"/>
</resultMap>
?
<!-- User findByIdUseResultMap(Long userId); -->
<select id="findByIdUseResultMap" parameterType="java.lang.Long" resultMap="myResultMap">SELECTuser_id uid, username, password, nick_name name, is_admin, phone, gender sex, birth, user_status, user_create_time ctime, user_update_time, is_delete, is_member, balanceFROMt_userWHERE user_id = #{userId}
</select>
八、全局配置文件【了解】
-
現在:會
-
以后:配置文件不見了,放到Spring中
1、properties
<!--properties : 加載外部properties文件resource : properties文件基于classpath的路徑
-->
<properties resource="jdbc.properties" />
2、settings
<!-- 全局設置 -->
<settings><!-- 開啟駝峰映射 --><setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
3、typeAliases
<!-- 別名設置 -->
<typeAliases><!-- 單個取別名 --><!--<typeAlias type="com.qf.java2107.pojo.User" alias="user"></typeAlias><typeAlias type="com.qf.java2107.pojo.Student" alias="student"></typeAlias>--><!-- 批量取別名,默認別名是類名,別名不區分大小寫 --><package name="com.qf.java2107.pojo"/>
</typeAliases>
4、plugins
4.1 分頁插件概述
4.2 使用步驟
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.10</version>
</dependency>
<plugins><!-- com.github.pagehelper為PageHelper類所在包名 --><plugin interceptor="com.github.pagehelper.PageInterceptor"><!-- 配置方言,不配置,則使用數據庫連接來判斷 --><property name="helperDialect" value="mysql"/><!-- 合理化參數 --><property name="reasonable" value="true"/></plugin>
</plugins>
-
使用
<!-- List<User> findAll(); -->
<select id="findAll" resultType="User">select * from t_user
</select> /*** 分頁**/
@Test
public void Test() throws Exception {IUserMapper userMapper = sqlSession.getMapper(IUserMapper.class);
?//分頁設置跟查詢之間不要出現其他操作//參數一:頁碼//參數二:顯示條數PageHelper.startPage(3, 5);List<User> list = userMapper.findAll();
?PageInfo<User> pageInfo = new PageInfo<>(list);System.out.println("當前頁:" + pageInfo.getPageNum());System.out.println("當前頁集合:" + pageInfo.getList());System.out.println("總頁數:" + pageInfo.getPages());System.out.println("總條數:" + pageInfo.getTotal());System.out.println("顯示條數:" + pageInfo.getPageSize()); ?//顯示條數System.out.println("實際顯示條數:" + pageInfo.getSize()); ?//實際顯示條數
?
}
5、environments
<!-- 環境配置 -->
<!--default 默認使用哪個環境,這個值是指environments下的某個environment子標簽的id屬性-->
<environments default="mysqldb"><!--mysql環境id :就是當前環境的唯一標識,可能被environments的default引用--><environment id="mysqldb"><!--transactionManager : 事務管理器type : JDBC--><transactionManager type="JDBC"></transactionManager><!--dataSource : 數據源type : POOLED 池化
?--><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment><!-- oracle環境 --><!--<environment id="oracledb"><transactionManager type="JDBC"></transactionManager><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment>-->
</environments>
6、mappers
<!-- 加載mapper映射文件 -->
<mappers><!--mapper : 加載單個mapper映射文件resource :基于classpath路徑下的mapper映射文件class : 基于mapper接口,mybatis注解開發方式。寫mapper接口全類名--><!--<mapper resource="com/qf/java2107/mapper/IUserMapper.xml" ></mapper>--><!--批量加載mapper映射文件要求:mapper映射文件跟mapper接口在編譯后必須在同一個路徑下--><package name="com.qf.java2107.mapper"/>
</mappers>
九、連表查詢
1、表與表之間的關系
-
數據庫層面
-
一對多:部門對員工、公司對部門
-
多對多:項目跟程序員、學生跟老師
-
多對一:學生對班級、員工對部門
-
一對一:人跟身份證、旅客跟護照
-
mybatis層面
2、部門表跟員工表為例
-
一對多:查詢部門關聯查詢員工
-
一對一:查詢員工關聯查詢部門
2.1 準備工作
CREATE TABLE `t_department` (`id` INT(11) NOT NULL AUTO_INCREMENT,`dept_name` VARCHAR(20) NOT NULL,PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
?
INSERT ?INTO `t_department`(`id`,`dept_name`) VALUES
(1,'研發部'),
(2,'市場部'),
(3,'財務部'),
(4,'測試部');
?
?
CREATE TABLE `t_employee` (`id` INT(11) NOT NULL AUTO_INCREMENT,`emp_name` VARCHAR(20) NOT NULL,`gender` INT(1) DEFAULT NULL COMMENT '1:男 0:女',`birthday` DATE DEFAULT NULL,`hire_date` DATETIME DEFAULT NULL,`salary` INT(11) DEFAULT NULL,`address` VARCHAR(200) DEFAULT NULL,`dept_id` INT(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;
?
?
INSERT ?INTO `t_employee`(`id`,`emp_name`,`gender`,`birthday`,`hire_date`,`salary`,`address`,`dept_id`) VALUES
(1,'寶寶',0,'2000-10-31','2021-10-01 09:00:00',8000,'杭州江干',2),
(2,'李四',1,'1985-11-10','2006-12-12 18:10:10',9000,'李家村',1),
(3,'王五',0,'1991-10-02','2009-12-02 00:00:00',1500,'王家村',2),
(5,'測試更新2',1,'2021-10-04','2021-11-11 00:00:00',15000,'杭州',2),
(7,'大CC',1,'2019-05-12','2021-11-07 00:00:00',6000,'杭州',2),
(8,'DD',1,'2021-11-05','2021-11-05 00:00:00',6000,'杭州',1),
(9,'九妹',0,'2021-11-11','2005-12-06 00:00:00',11111,'遠古時期',NULL),
(10,'蕭炎',1,'1999-12-12','2021-02-03 00:00:00',5000,'牛田村',1),
(11,'蕭媚',1,'1985-11-11','2006-12-12 00:00:00',9000,'李家村',1),
(12,'小醫仙',0,'1991-10-02','2009-12-02 00:00:00',1500,'王家村',2),
(13,'林動',1,'2021-11-05','2021-11-05 00:00:00',6000,'杭州',1),
(14,'凌青竹',1,'2021-11-05','2021-11-05 00:00:00',6000,'杭州',1),
(15,'紀寧',1,'2021-11-05','2021-11-05 00:00:00',6000,'杭州',2),
(16,'北冥',1,'2021-11-05','2021-11-05 00:00:00',6000,'杭州',1),
(17,'葉伏天',0,'2021-11-11','2005-12-06 00:00:00',11111,'遠古時期',NULL),
(18,'余生',0,'2021-11-11','2005-12-06 00:00:00',11111,'遠古時期',2),
(19,'花解語',0,'2021-11-11','2005-12-06 00:00:00',11111,'遠古時期',1),
(100,'張三',1,'1999-12-12','2021-02-03 00:00:00',5000,'牛田村',1);
2.2 一對多
2.2.1 修改部門實體
2.2.2 Mapper接口和Mapper映射文件
public interface IDepartmentMapper {
?Department findByIdAndEmps(Integer id);
?
}
? ?<resultMap id="DeptAndEmpsResultMap" type="com.qf.java2107.pojo.Department" extends="BaseResultMap">
?<!-- 映射一對多【集合】 --><!--collection: 映射一對多【集合】property: 集合名ofType : 集合中的元素類型--><collection property="employees" ofType="com.qf.java2107.pojo.Employee"><!-- 映射單個員工 --><id column="emp_id" property="id"/><result column="emp_name" property="empName"/><result column="gender" property="gender"/><result column="birthday" property="birthday"/><result column="hire_date" property="hireDate"/><result column="salary" property="salary"/><result column="address" property="address"/><result column="dept_id" property="deptId"/></collection></resultMap>
?<resultMap id="BaseResultMap" type="com.qf.java2107.pojo.Department"><id column="id" property="id"/><result column="dept_name" property="deptName"/></resultMap>
?<!-- Department findByIdAndEmps(Integer id); --><select id="findByIdAndEmps" parameterType="int" resultMap="DeptAndEmpsResultMap">SELECTd.id,d.dept_name,e.id emp_id,e.emp_name,e.gender,e.birthday,e.hire_date,e.salary,e.address,e.dept_idFROMt_department d, t_employee eWHERE d.id = e.dept_idAND d.id = #{id}</select>
2.3 一對一
2.3.1 修改員工實體
2.3.2 Mapper接口和Mapper映射文件
public interface IEmployeeMapper {
?Employee findByIdAndDept(Integer id);
?
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
?
<mapper namespace="com.qf.java2107.mapper.IEmployeeMapper">
?<resultMap id="BaseResultMap" type="com.qf.java2107.pojo.Employee"><id column="id" property="id"/><result column="emp_name" property="empName"/><result column="gender" property="gender"/><result column="birthday" property="birthday"/><result column="hire_date" property="hireDate"/><result column="salary" property="salary"/><result column="address" property="address"/><result column="dept_id" property="deptId"/></resultMap>
?<resultMap id="EmpAndDeptResultMap" type="com.qf.java2107.pojo.Employee" extends="BaseResultMap"><!--association : 映射實體property : 實體屬性名javaType : 實體屬性全類名--><association property="department" javaType="com.qf.java2107.pojo.Department"><id column="did" property="id"/><result column="dept_name" property="deptName"/></association></resultMap>
?<!-- Employee findByIdAndDept(Integer id); --><select id="findByIdAndDept" parameterType="int" resultMap="EmpAndDeptResultMap">SELECTe.id id,e.emp_name,e.gender,e.birthday,e.hire_date,e.salary,e.address,e.dept_id,d.id did,d.dept_nameFROMt_employee e JOIN t_department dON e.dept_id = d.idWHERE e.id = #{id}</select>
</mapper>
十、分步查詢、延遲加載
1、分步查詢
2、一對多
2.1 IDeparmentMapper映射文件
<!-- =================分步查詢====================== -->
<resultMap id="DeptAndEmpStepQueryResultMap" type="com.qf.java2107.pojo.Department"><id column="id" property="id"/><result column="dept_name" property="deptName"/><!-- 映射集合 --><collection property="employees" ofType="com.qf.java2107.pojo.Employee"select="com.qf.java2107.mapper.IEmployeeMapper.findByDeptId" column="id"></collection>
</resultMap><!--Department findByIdUseStepQuery(Integer id);-->
<select id="findByIdUseStepQuery" parameterType="int" resultMap="DeptAndEmpStepQueryResultMap">SELECT id, dept_name FROM t_department WHERE id = #{id}
</select>
2.2 IEmployeeMapper映射文件
<!--==================分步查詢相關======================== -->
<!--List<Employee> findByDeptId(Integer deptId);-->
<select id="findByDeptId" parameterType="int" resultMap="BaseResultMap">SELECT * FROM t_employee WHERE dept_id = #{deptId}
</select>
2.3 執行流程
3、延遲加載【面試題】
也叫懶加載,也叫按需加載
當需要使用到關聯的數據時,才去執行查詢操作
實現原理:Cglib動態代理【基于繼承】
延遲加載只會出現在分步查詢中。一般延遲加載的數據都是大數據【如集合】
3.1 具體實現
十一、動態SQL
-
if
-
choose (when, otherwise)
-
trim (where, set)
-
foreach
1、if
2、where
<!-- List<Employee> findWithIf(Employee employee); -->
<select id="findWithIf" parameterType="com.qf.java2107.pojo.Employee" resultType="com.qf.java2107.pojo.Employee">SELECT * FROM t_employee<!--WHERE 1=1--><!-- where 會忽略條件成立的最前面的多余的and或者or --><where><if test="empName != null and empName.trim() != ''">AND emp_name LIKE #{empName}</if><if test="salary != null and salary > 0">AND salary = #{salary}</if><if test="gender == 0 || gender == 1">AND gender = #{gender}</if><if test="deptId != null">AND dept_id = #{deptId} </if><!-- 除SQL之外的地方都是JavaBean的屬性名 --></where>
</select>
3、trim【理解】
<!-- List<Employee> findWithTrim(Employee employee); --><select id="findWithTrim" parameterType="com.qf.java2107.pojo.Employee" resultType="com.qf.java2107.pojo.Employee">SELECT * FROM t_employee<!--prefix : 要加的前綴prefixOverrides : 要去掉的前綴suffix : 要加的后綴suffixOverrides : 要去掉的后綴--><!--<trim prefix="where" prefixOverrides="and | or" suffix="" suffixOverrides=""><if test="empName != null and empName.trim() != ''">AND emp_name LIKE #{empName}</if><if test="salary != null and salary > 0">AND salary = #{salary}</if><if test="gender == 0 || gender == 1">AND gender = #{gender}</if><if test="deptId != null">AND dept_id = #{deptId}</if></trim>--><trim prefix="where" prefixOverrides="" suffix="" suffixOverrides="AND | OR"><if test="empName != null and empName.trim() != ''">emp_name LIKE #{empName} AND</if><if test="salary != null and salary > 0">salary = #{salary} AND</if><if test="gender == 0 || gender == 1">gender = #{gender} AND</if><if test="deptId != null">dept_id = #{deptId} AND</if></trim></select>
4、forEach
<!-- List<Employee> findByIds(List<Integer> ids); -->
<select id="findByIds" parameterType="list" resultType="com.qf.java2107.pojo.Employee"><!--SELECT * FROM t_employee WHERE id IN (1,25,3,62)-->SELECT * FROM t_employee<where><if test="list != null and list.size() > 0"><!--id IN (1,25,3,62)--><!--collection : 要遍歷的集合,可以使用別名,但是如果使用了@Param指定入參key,那么就指定這個keyitem : 正在迭代的元素名,自己起名separator : 元素之間的分隔符open : 要遍歷的元素開始之前的SQL片段close : 要遍歷的元素結束之后的SQL片段--><foreach collection="list" item="id" separator="," open="id IN (" close=")">#{id}</foreach></if></where>
</select>
5、choose...when...otherwise【了解】
<!-- List<Employee> findWithChoose(Employee employee); -->
<select id="findWithChoose" parameterType="com.qf.java2107.pojo.Employee" resultType="com.qf.java2107.pojo.Employee">SELECT * FROM t_employee<where><choose><when test="empName != null and empName.trim() != ''">AND emp_name LIKE #{empName}</when><when test="salary != null and salary > 0">AND salary = #{salary}</when><when test="gender == 0 or gender == 1">AND gender = #{gender}</when><otherwise>dept_id = 1</otherwise></choose></where>
</select>
6、sql...include
<!-- List<Employee> findByIds(List<Integer> ids); --><select id="findByIds" parameterType="list" resultType="com.qf.java2107.pojo.Employee"><include refid="BaseSelect"></include><where><if test="list != null and list.size() > 0"><foreach collection="list" item="id" separator="," open="id IN (" close=")">#{id}</foreach></if></where></select><sql id="BaseSelect">SELECT<include refid="BaseColumn"></include>FROM t_employee</sql><sql id="BaseColumn">id,emp_name,gender,birthday,hire_date,salary,address,dept_id</sql>
7、set
<!-- int updateWithSet(Employee employee); -->
<update id="updateWithSet" parameterType="Employee">update t_employee<set><if test="empName != null and empName.trim() != ''">emp_name = #{empName},</if><if test="salary != null and salary > 0">salary = #{salary},</if><if test="gender == 0 or gender == 1">gender = #{gender},</if></set>where id = #{id}
</update>
十二、緩存機制【理解】
1、分類
2、區別
-
一級緩存
-
級別:SqlSession
-
存儲介質:內存
-
存儲類型:對象副本
-
失效情況
-
二級緩存
-
級別:NameSpace
-
存儲介質:磁盤
-
存儲類型:散裝數據
-
觸發條件
3、Mybatis執行查詢流程
4、一級緩存
@Test
public void firstLevelCacheTest() throws Exception {IEmployeeMapper employeeMapper = sqlSession.getMapper(IEmployeeMapper.class);Employee employee1 = employeeMapper.findById(10);System.out.println(employee1);//1.兩個SqlSession//sqlSession = factory.openSession();//employeeMapper = sqlSession.getMapper(IEmployeeMapper.class);//2.執行增刪改//employeeMapper.deleteById(111111);//3.手動清空緩存//sqlSession.clearCache();//4.手動提交事務sqlSession.commit();Employee employee2 = employeeMapper.findById(10);System.out.println(employee2);System.out.println(employee1 == employee2);}
5、二級緩存
-
二級緩存默認開啟,我們可以通過配置文件對其關閉
-
二級緩存
-
實現步驟
/*** 二級緩存**/
@Test
public void secondLevelCacheTest() throws Exception {IEmployeeMapper employeeMapper = sqlSession.getMapper(IEmployeeMapper.class);Employee employee1 = employeeMapper.findById(10);System.out.println(employee1);sqlSession.close();sqlSession = factory.openSession();employeeMapper = sqlSession.getMapper(IEmployeeMapper.class);Employee employee2 = employeeMapper.findById(10);System.out.println(employee2);System.out.println(employee1 == employee2);}
十三、#{}和${}的區別
優先選擇#{}取值,如果不行,則使用${}
十四、注解開發【會用】
package com.qf.java2107.mapper;import com.qf.java2107.pojo.Department;
import org.apache.ibatis.annotations.*;import java.util.List;/*** @author ghy* @version 1.0* @date 2021-12-27**/
public interface IDepartmentMapper {@Insert("insert into t_department (dept_name) values (#{deptName})")@SelectKey(statement = "select last_insert_id()",keyProperty = "id",keyColumn = "dept_id",before = false,resultType = int.class)int save(Department department);/*** @Results 等同于配置文件的resultMap標簽* id 等同于配置文件的resultMap標簽中id屬性** @Result : 映射單個屬性,用boolean來區分是否是主鍵映射*/@Results(id = "BaseResultMap",value = {@Result(id = true, column = "id", property = "id"),@Result(id = false, column = "dept_name", property = "deptName")})@Select("select id, dept_name from t_department")List<Department> findAll();@ResultMap("BaseResultMap") //引用其他已經定義好的ResultMap@Select("select id, dept_name from t_department where id = #{id}")Department findById(Integer id);}
package com.qf.java2107.mapper;import com.qf.java2107.pojo.Employee;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.mapping.FetchType;/*** @author ghy* @version 1.0* @date 2021-12-27**/
public interface IEmployeeAnnoMapper {/*** 根據ID查詢員工關聯部門* @param id* @return*/@Results({@Result(id = true, column = "id", property = "id"),@Result(id = false, column = "emp_name", property = "empName"),@Result(id = false, column = "gender", property = "gender"),@Result(id = false, column = "birthday", property = "birthday"),@Result(id = false, column = "hire_date", property = "hireDate"),@Result(id = false, column = "salary", property = "salary"),@Result(id = false, column = "address", property = "address"),@Result(id = false, column = "dept_id", property = "deptId"),@Result(id = false, property = "dept", column = "dept_id",//one 一對一映射one = @One(select = "com.qf.java2107.mapper.IDepartmentMapper.findById",fetchType = FetchType.LAZY))})@Select("select * from t_employee where id = #{id}") //dept_idEmployee findByIdUseStep(Integer id);}
十五、源碼分析【聽一遍】
1、查詢
2、增刪改方法
十六、面試題
1、Mybatis支持延遲加載嗎?
2、#{}和${}的區別
3、Mybatis應用到的設計模式
4、Mybatis的Mapper接口是否支持方法重載
5、Mybatis的Mapper映射文件的標簽,你知道哪些?
-
除之前講的之外
-
sql:抽取的SQL片段
-
include:引用抽取的SQL片段
<!-- List<Employee> findByIds(List<Integer> ids); --><select id="findByIds" parameterType="list" resultType="com.qf.java2107.pojo.Employee"><include refid="BaseSelect"></include><where><if test="list != null and list.size() > 0"><foreach collection="list" item="id" separator="," open="id IN (" close=")">#{id}</foreach></if></where></select><sql id="BaseSelect">SELECT<include refid="BaseColumn"></include>FROM t_employee</sql><sql id="BaseColumn">id,emp_name,gender,birthday,hire_date,salary,address,dept_id</sql>
總結
以上是生活随笔為你收集整理的【MyBatis】基础全网最全,看这篇就够了的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。