日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【MyBatis】基础全网最全,看这篇就够了

發布時間:2023/12/15 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【MyBatis】基础全网最全,看这篇就够了 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、原始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框架

  • 通過ORM框架解決JDBC存在的問題

1、ORM

  • Object Relation Mapping:對象關系映射

Java對象數據庫表
類名表名
屬性名列名【字段名】
對象行【記錄】

2、框架

  • 概述:就是一個半成品軟件

    • 需要使用框架幫我們完成JavaEE應用的開發

  • 作用

    • 能夠幫我們快速有效的開發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; ? }
    • Mapper接口

    public interface IUserMapper { ?/*** 查詢所有* @return*/List<User> findAll(); ? }
    • SQL【Mapper】映射文件

    <?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、增加

    • Mapper接口

    /*** 增加* @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 主鍵回填

    • 主鍵自增

      • 方式一【Mapper映射文件】

      <!--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; ? }

    • Mapper接口和映射文件

    <?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.properties】

    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關閉所有日志記錄開關;是最高等級的,用于關閉所有日志記錄。
    • 直接使用API即可

    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、映射規則

    • 當查詢結果集的列名跟JavaBean屬性名相同時,自動映射

    • 當查詢結果集的列名跟JavaBean屬性名不相同時,需要手動映射

    2、不滿足映射規則

    • 如果滿足駝峰

      • 使用別名進行映射【但是SQL太長】

      <!-- 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>
      • 全局配置文件【mybatis-config.xml】開啟駝峰映射

      <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

    • 自定義結果集映射

      • mybatis內部已經集成了結果集映射,就是Mapper映射文件的resultType屬性。resultType底層使用其實也是ResultMap

      • resultType和resultMap最好只使用一個

        • 如果滿足駝峰并且不使用別名的情況下,可以使用resultType

        • resultMap可以在查詢結果集封裝中自定義使用。連表查詢只能使用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> resultMap的使用

    八、全局配置文件【了解】

    • 現在:會

    • 以后:配置文件不見了,放到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 分頁插件概述

    • 可以屏蔽底層數據庫的差異,實現同一API實現不同數據庫的分頁功能

    • Mybatis_PageHelper: Mybatis分頁插件

    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>
    • 使用

      • Mapper映射文件

      <!-- 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映射文件

    <!-- 加載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 一對多

    • 根據ID查詢部門信息且關聯員工信息

    2.2.1 修改部門實體

    修改部門實體

    2.2.2 Mapper接口和Mapper映射文件

    Mapper接口和Mapper映射文件

    • Mapper接口

    public interface IDepartmentMapper { ?Department findByIdAndEmps(Integer id); ? }
    • Mapper映射文件

    ? ?<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 一對一

    • 根據ID查詢員工信息且關聯部門信息

    2.3.1 修改員工實體

    修改員工實體

    2.3.2 Mapper接口和Mapper映射文件

    Mapper接口和Mapper映射文件

    • Mapper接口

    public interface IEmployeeMapper { ?Employee findByIdAndDept(Integer id); ? }
    • Mapper映射文件

    <?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、分步查詢

    • 是連表查詢的另一種方式

      • 把連表查詢的SQL進行拆分出多個單表查詢的SQL

    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動態代理【基于繼承】

    延遲加載只會出現在分步查詢中。一般延遲加載的數據都是大數據【如集合】

    • 即時加載:先執行完所有的SQL,再打印數據

    • 延遲加載,先執行需要獲取數據的SQL,再打印數據。后面如果還需要獲取數據,再執行SQL,再打印數據

    3.1 具體實現

    • 全局配置文件開啟延遲加載的開頭

    全局配置文件開啟延遲加載的開頭

    • DepartmentMapper接口和映射文件

    DepartmentMapper接口和映射文件

    • 測試

    即時加載

    延遲加載

    十一、動態SQL

    • if

    • choose (when, otherwise)

    • trim (where, set)

    • foreach

    1、if

    • 條件判斷

      • 成立,就拼接SQL

    2、where

    • 功能相當于數據庫的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【理解】

    • 可以自定義的拼接或去掉SQL片段前后綴

    <!-- 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

    • 僅用于更新,跟if配套使用

    <!-- 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執行查詢流程

    Mybatis執行查詢流程

    4、一級緩存

    • 一級緩存默認開啟,我們無法關閉他

    • 在執行兩次相同的查詢時,第一次會向數據庫發送SQL,并且寫入一份到一級緩存中,那么后面的查詢操作就直接從緩存中獲取數據。不會向數據庫發送SQL

    • 一級緩存失效的情況

      • 不是同一個SqlSession

      • 兩次相同的查詢中間執行增刪改

      • 兩次相同的查詢中間手動清空緩存

      • 兩次相同的查詢中間手動提交事務

    @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、二級緩存

    • 二級緩存默認開啟,我們可以通過配置文件對其關閉

    • 二級緩存

      • 必須在SqlSession關閉之后,數據才會被寫入到二級緩存中。

      • 存儲介質是磁盤,所以寫入的字節數據,那么要被寫入的對象所在的類必須實現Serializable接口

    • 實現步驟

      • 全局配置文件開啟

      • 在要使用二級緩存的namespace中配置一個<cache/>標簽

      • 關閉SqlSession

    /*** 二級緩存**/ @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);}

    十三、#{}和${}的區別

    • #{}

      • 在填充參數時,是通過?占位符的方式,能夠避免SQL注入

      • 只是獲取跟數據庫表列相關的值

    • ${}

      • 在填充參數時,使用的是直接進行字符串拼接,會有SQL注入的風險

      • 使用其可以操作非數據庫表列的取值

    優先選擇#{}取值,如果不行,則使用${}

    十四、注解開發【會用】

    • 注解開發跟配置文件開發,選擇一種

    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);}
    • 分步查詢【IEmployeeAnnoMapper.class】

    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、查詢

    • 查詢單個

      • DefaultSqlSession的selectOne方法

        • DefaultSqlSession的selectList方法,得到結果后,進行集合數量判斷,如果是1,直接返回。>1,否則就報錯。0返回null

          • CachingExecutor的query方法

            • BaseExecutor的query方法

              • BaseExecutor的queryFromDatabase方法

                • BaseExecutor的doQuery方法

                  • 通過SimpleExecutor中去調用JDBC的execute()

    • 查詢集合

      • DefaultSqlSession的selectList方法,得到結果后,直接返回

        • CachingExecutor的query方法

          • BaseExecutor的query方法

            • BaseExecutor的queryFromDatabase方法

              • BaseExecutor的doQuery方法

                • 通過SimpleExecutor中去調用JDBC的execute()

    2、增刪改方法

    • 修改

      • DefaultSqlSession的update方法

        • CachingExecutor的update方法:會清空緩存操作

          • BaseExecutor的doUpdate方法

            • 通過SimpleExecutor中去調用JDBC的execute()

    • 增加、刪除

      • 先調用DefaultSqlSession的insert方法或者delete方法

        • 接下來就會執行DefaultSqlSession的update方法

    十六、面試題

    1、Mybatis支持延遲加載嗎?

    2、#{}和${}的區別

    3、Mybatis應用到的設計模式

    • 構建者模式

    • 工廠模式

    • 代理模式

    4、Mybatis的Mapper接口是否支持方法重載

    • 不支持

      • mapper接口的方法名就是mapper映射文件的statementId,是用來獲取執行SQL的唯一標識

    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】基础全网最全,看这篇就够了的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。