1. 程式人生 > 其它 >狂神mybatis學習筆記

狂神mybatis學習筆記

1、mybatis簡介

MyBatis 是一款優秀的持久層框架
   	它支援定製化 SQL、儲存過程以及高階對映。
    MyBatis 避免了幾乎所有的  JDBC程式碼、手動設定引數以及獲取結果集。
    MyBatis 可以使用簡單的XML,將Java 的 POJO對映成資料庫中的記錄。

2、mybatis使用過程

//1.maven工程匯入依賴,非maven工程匯入jar包
	<!-- mysql -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.28</version>
	</dependency>
    <!-- mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.9</version>
	</dependency>
	<!-- log4j -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
//2.建立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>
        <!--1.引入外部檔案-->
        <properties resource="db.properties"/>
        <!--2.設定引數-->
        <settings>
            <setting name="logImpl" value="LOG4J"/>
        </settings>
        <!--3.給pojo起別名-->
        <typeAliases>
            <package name="pojo"/>
        </typeAliases>
        <!--4.環境引數 -->
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="${driver}"/>
                    <property name="url" value="${url}"/>
                    <property name="username" value="${username}"/>
                    <property name="password" value="${password}"/>
                </dataSource>
            </environment>
        </environments>
        <!--5.註冊mappers-->
        <mappers>
            <mapper resource="mapper/userMapper.xml"/>
        </mappers>
    </configuration>
//3.建立MybatisUtils工具類
    package mapper;

    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;

    import java.io.IOException;
    import java.io.InputStream;

    public class MybatisUtils {
        private static String resource;
        private static InputStream inputStream;
        private static SqlSessionFactory sqlSessionFactory;

        static {
            resource = "mybatis-config.xml";
            try {
                inputStream = Resources.getResourceAsStream(resource);
            } catch (IOException e) {
                e.printStackTrace();
            }
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }

        public static SqlSession getSqlSession(){
            return sqlSessionFactory.openSession();
        }
    }
//4.建立實體類
	package pojo;

    public class User {
        private Integer id;
        private String name;
        private Integer age;

        public User() {
        }

        public User(Integer id, String name, Integer age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }
    }
//5.建立持久層介面UserMapper
    package mapper;

    import pojo.User;

    import java.util.List;

    public interface UserMapper {
        List<User> selectUser();
    }
//6.建立與介面對應的userMapper.xml
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="mapper.UserMapper">
      <select id="selectUser" resultType="pojo.User">
        select * from User
      </select>
    </mapper>
//7.簡單使用
    @Test
    public void test01(){
        SqlSession session = null;
        try {
            session = MybatisUtils.getSqlSession();
            UserMapper mapper = session.getMapper(UserMapper.class);
            List<User> list = mapper.selectUser();
            list.forEach(System.out::println);
        }finally {
            if(session!=null){
                session.close();
            }
        }
    }
	@Test
    public void test03(){
        SqlSession session = null;
        try {
            session = MybatisUtils.getSqlSession();
            UserMapper mapper = session.getMapper(UserMapper.class);
            User user = new User(null, "李四", 28);
            mapper.addUser(user);
            session.commit();
        }finally {
            if(session!=null){
                session.close();
            }
        }
    }

3、mybatis過程解析

//1.mybatis-config.xml
	該配置檔案時mybatis的核心配置檔案,在這裡面手動設定了資料庫連線引數,以及註冊mappers(介面對映的xml檔案)
    因此,java只需要讀取這一個配置檔案就能把相關的非java檔案都讀取到了
//2.UserMapper
    該類存在的必要性其實就是單純使用userMapper.xml無法在java層面呼叫方法,需要userMapper做一個媒介
    並且可以在介面中定義持久層實現的規範
//3.userMapper.xml
    該對映xml檔案的作用就是書寫SQL語句,其內建了mapper標籤可與介面繫結,增刪改查標籤可與介面中的方法繫結
    語句執行後返回增刪改查標籤中約定的type或者map型別
//4.一切就緒,如何使用
    想在java層面去呼叫非java檔案的內容,必須要先讀取資源
    讀取之後,
        由會話工廠構造器去構建會話工廠//會話工廠就對應mybatis的最高一級
    	由會話工廠開啟一個會話
        //上述步驟封裝成工具類了
    	由會話獲取對映
    	由對映執行具體方法
//5.mybatis預設開啟事務
	在增刪改的方法呼叫時,別忘了commit提交事務
    如果業務不需要事務處理,也可以在開啟session會話的時候直接使用 openSession(true)過載的方式設定預設提交事務

4、小問題

//1.如果資料庫列名跟pojo中屬性名不一致
	解決方案一:
        查詢時給列名起別名
    解決方案二:
        使用resultMap標籤設定屬性跟列的匹配
        1>新增resultMap標籤
        	<resultMap id="userResultMap" type="User">
                <result property="name" column="username"/>
                <result property="pwd" column="password"/>
            </resultMap>
        2>設定增刪改查標籤的返回值為resultMap
        	<select id="selectUser" resultMap="userResultMap">
                select * from user
            </select>
//2.userMapper.xml中
    如果有傳參的SQL語句,使用#{xx}來設定引數
    推薦跟繫結的介面放在同一包下

5、mybatis核心配置檔案

//1.properties
	作用,引入外部檔案,通常是db.properties,log4j.properties
    <properties resource="db.properties"/>
//2.settings
    作用,改變 MyBatis 的執行時行為,通常使用預設即可,如有需求自主配置
    <settings>
        <setting name="logImpl" value="LOG4J"/>
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>
//3.typeAliases
   	作用,給pojo起別名
    <typeAliases>
        //第一種,單個的,可以DIY
        <typeAlias type="pojo.User" alias="User"/>
        //第二種,直接掃描實體類的包,名字預設就是實體類的名字首字母小寫,推薦使用
        <package name="pojo"/>
    </typeAliases>
//4.enviroments
    作用,環境配置,設定事務管理和資料來源,預設事務管理是jdbc,預設資料來源是pooled
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
//5.mappers
    作用,註冊mapper,把與介面繫結的xml檔案註冊進mybatis核心檔案中
    <mappers>
        //第一種,注意,resource如果有多級目錄,需要用/分割而不能使用.去分割,推薦使用
        <mapper resource="userMapper.xml"/>
        //第二種,類的方式,xml必須放在mapper介面包下,而且名字必須一致
        <mapper class="UserMapper"/>
        //第三種,包掃描的方式,xml必須放在mapper介面包下,而且名字必須一致
        <package name="mapper"/>
    </mappers>

6、mybatis四大核心物件

//1.Sql Session Factory Builder
//2.Sql Session Factory
//3.Sql Session
//4.Mapper
builder載入核心配置檔案=》factory開啟會話=》session載入介面=》mapper執行方法

7、日誌

//1.日誌有什麼用
	作用,列印執行過程中的一些內容,便於排錯
//2.mybatis中日誌怎麼用
    //在mybatis核心配置檔案中設定日誌實現
    <settings>
        //STDOUT_LOGGING是mybatis內建的標準日誌,可以直接使用,
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
//3.除了STDOUT_LOGGING我們還需要掌握的日誌是LOG4J
    1>匯入log4j依賴
        <!-- log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
	2>建立log4j.properties
        # 定義輸出級別為debug,輸出名稱為stdout
        log4j.rootLogger=debug,stdout
        # 定義stdout的輸出採用哪個類來執行
        log4j.appender.stdout=org.apache.log4j.ConsoleAppender
        # 定義stdout的輸出型別的樣式佈局
        log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
        # 定義stdout樣式佈局的訊息格式
        log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
        //上述都是最基本的,有需求直接去搜一個完整的,不需要記憶
	3>在mybatis核心配置檔案中設定日誌實現
        <settings>
            <setting name="logImpl" value="LOG4J"/>
        </settings>  
    4>log4j的簡單使用
        import org.apache.log4j.Logger;
        static Logger logger = Logger.getLogger(M1.class);
		logger.info()、logger.debug()、logger.error()

8、limit分頁

//1.dao層
  	@Test
    public void testLimit(){
        SqlSession session = null;
        try {
            session = MybatisUtils.getSqlSession();
            UserMapper mapper = session.getMapper(UserMapper.class);
            
            HashMap<String, Integer> map = new HashMap<>();
            //通過map集合傳給資料庫一個起始值,一個頁容量
            map.put("startIndex",2);
            map.put("pageSize",5);
            
            List<User> list = mapper.queryUserByLimit(map);
            list.forEach(System.out::println);
        }finally {
            if(session!=null){
                session.close();
            }
        }
    }
//2.mapper.xml
	<select id="queryUserByLimit" parameterType="map" resultMap="userResultMap">
        select * from user limit #{startIndex},#{pageSize}
    </select>

9、使用註解開發

//1.註解如何使用
	當我們使用註解時,就不需要在把這個語句寫入mapper.xml了
    1>在核心配置檔案中繫結介面
        <mappers>
        	<mapper class="mapper.UserMapper"/>
    	</mappers>
    2>在介面中的方法上新增需要的註解
        @Select("select * from user")
        List<User> selectUser();
	3>測試
//2.常用註解
    @Select
    @Insert
   	@Update
    @Delete
   	@Result
    @Results
   	@ResultMap
    @Param
    //查詢程式碼示例,增刪改同理
        @Select("select * from user")
        @Results(id = "userResultMap", value={
                @Result(property = "name",column = "username",javaType = String.class),
                @Result(property = "pwd",column = "password",javaType = Integer.class)
        })
        List<User> selectUser();
        @Select("select * from user where id=#{id}")
        @ResultMap("userResultMap")
        User queryUserById(@Param("id") Integer id);    
    //這四個關係到多對應結果集對映,動態SQL,快取,複雜程度高,建議直接用xml得了
    @One
    @Many
    @SelectProvider
    @CacheNamespace
//3.註解總結
	雖然省略了xml檔案的書寫,但是如果sql語句非常複雜時,註解的方式反而弄巧成拙
    當然,作為一名合格的程式設計師,要能做到在xml和註解的方式中靈活切換(主要自己說了不算=.=)

10、lombok

//1.lombok是什麼
	外掛,構建工具
//2.lombok能幹什麼
    簡化pojo建立
//3.lombok怎麼用
    1>idea安裝lombok外掛
   	2>匯入maven依賴
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
            <scope>provided</scope>
        </dependency>
    3>在pojo上加註解
        @NoArgsConstructor
        @AllArgsConstructor
        @Data
        public class User {
            private Integer id;
            private String name;
            private Integer pwd;
        }
//4.總結
	不能實現構造器過載,需要手動新增
    屬於黃階心法,連玄階都夠不上,可用可不用

11、多對一

//1.第一種方式
	<!--子查詢-->
    <select id="selectStudent" resultMap="selectStudent">
        select * from student
    </select>
    <resultMap id="selectStudent" type="Student">
        <association property="teacher" column="tid" select="selectTeacherById"/>
    </resultMap>
    <select id="selectTeacherById" resultType="teacher">
        select * from teacher where id=#{tid}
    </select>
    
    //resultMap下除了關聯欄位都可以省略
    //association中的column屬性就是傳值
    //在子查詢中,傳值不需要parameterType屬性,而且#{xx}的xx可以隨便寫,當然最好跟傳值一致
       
//2.第二種方式
    <!--聯表查詢-->
    <select id="selectStudent2" resultMap="selectStudent2">
        select s.id,s.name,t.id _id,t.name _name from student s join teacher t on s.tid = t.id
    </select>
    <resultMap id="selectStudent2" type="Student">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <association property="teacher">
            <id property="id" column="_id"/>
            <result property="name" column="_name"/>
        </association>
    </resultMap>
        
    //resultMap下任何欄位都不可以省略
    //所有的column屬性值都是根據查詢結果集來的,因此要不能重複,起別名解決就行

12、一對多

//1.第一種方式
	<!--子查詢-->
    <select id="selectTeacher" resultMap="selectTeacher">
        select * from teacher where id=#{id}
    </select>
    <resultMap id="selectTeacher" type="Teacher">
        <id property="id" column="id"/>
        <collection property="list" column="id" ofType="Student" select="studentAdd"/>
    </resultMap>
    <select id="studentAdd" resultType="Student">
        select * from student where tid = #{id}
    </select>
    
    //resultMap下非關聯的非主鍵欄位可以省略
    //collection中的column屬性就是傳值,ofType是泛型型別
    //在子查詢中,傳值不需要parameterType屬性,而且#{xx}的xx可以隨便寫,當然最好跟傳值一致
    
//2.第二種方式
    <!--聯表查詢-->
    <select id="selectTeacher2" resultMap="selectTeacher2">
        select t.id,t.name,s.id _id,s.name _name, tid from teacher t join student s on t.id=s.tid
    </select>
    <resultMap id="selectTeacher2" type="Teacher">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <collection property="list" ofType="Student">
            <id property="id" column="_id"/>
            <result property="name" column="_name"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>
    
    //resultMap下任何欄位都不可以省略
    //collection中只需要寫泛型型別ofType
    //所有的column屬性值都是根據查詢結果集來的,因此要不能重複,起別名解決就行

13、動態SQL

//1.if
	<select id="selectBlog" parameterType="map" resultType="Blog">
        select * from blog where 1=1
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </select>
    注意點:
            1.傳參用hashmap,這樣可以隨意控制條件
            2.初始語句後面加一個where 1=1保證語法正確
            3.每個if的拼接語句都要字首一個and
//2.where
	上述語句中where 1=1是不符合規範的無奈之舉,我們可以使用where標籤來替換
    	<where>
            <if test="title != null">
                and title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </where>
	當if至少有一個滿足的時候,才新增where,並且第一個if拼接的語句中的開頭and會被去掉
//3.choose
    choose等於java中的switch,where等於case,otherwise等於default
    <select id="selectBlog" parameterType="map" resultType="Blog">
        select * from blog
        <where>
            <choose>
                <when test="title!=null">
                    and title = #{title}
                </when>
                <otherwise>
                    and 1=1
                </otherwise>
            </choose>
        </where>
    </select>
//4.set
    set 元素會動態前置 SET 關鍵字,同時也會刪掉最後一個逗號
    <update id="updateBlog" parameterType="map">
        update blog
        <set>
            <if test="title!=null">
                title=#{title},
            </if>
            <if test="author!=null">
                author=#{author},
            </if>
        </set>
        where id=#{id}
    </update>
//5.sql片段
    作用,抽取公共程式碼,在需要的地方引用,跟java中的方法意思差不多
    1>抽取程式碼
        <sql id="xx">
            <if test="title!=null">
                title=#{title},
            </if>
            <if test="author!=null">
                author=#{author},
            </if>
        </sql>
    2>引用
    	<include refid="xx"/>
    注意,where和set這種能幫助我們優化的東西不要抽取,僅僅抽取條件判斷或者普通的SQL語句就行
//6.foreach
   	作用,類似集合遍歷一樣
	<foreach item="item" collection="list" open="(" separator="," close=")">
		#{item}
  	</foreach>
    collection是集合 item是集合項 open是字首 separator是分隔符 close是字尾

14、快取

//1.快取幹嘛的
	當有大量客戶端頻繁訪問資料時,資料庫的壓力是非常大的,因此把常檢視且不常修改的資料放入快取,不走資料庫,減少資料庫的壓力
//2.一級快取
    mybatis預設開啟一級快取,作用在sqlSession範圍內
    ==========================================
        Opening JDBC Connection
        Created connection 2114684409.
        Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7e0b85f9]
        ==>  Preparing: select * from user where id = ?
        ==> Parameters: 1(Integer)
        <==    Columns: id, username, password
        <==        Row: 1, 老趙, 11
        <==      Total: 1
        User(id=1, username=老趙, password=11)
        User(id=1, username=老趙, password=11)
        true
        Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7e0b85f9]
        Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@7e0b85f9]
    ==========================================
    //查詢同一條資料,在一個sqlSession範圍內,只會執行一次SQL語句,第二次的查詢直接從快取中拿資料
    
    //一級快取是會失效的
		1.增刪改會清除快取
        2.手動清理session.clearCache()
//3.二級快取
    1>顯示設定二級快取,其實預設就是開啟的
		<setting name="cacheEnabled" value="true"/>
	2>在mapper.xml檔案
        <cache/>
    //這樣就開啟了二級快取
            
    //當一個session關閉時,一級快取的東西就會被序列化存入二級快取,然後別的session如果查詢相同內容就會從二級快取中取
    //因為快取類要被序列化因此要實現serializable介面
 
//4.這些東西看看熟悉下就行,後續會用Redis來做快取