Mybatis學習總結

1肥照、第一個Mybatis程序

思路:搭建環(huán)境->導入Mybatis->編寫代碼->測試

1.1搭建環(huán)境

搭建數(shù)據(jù)庫

create database `Mybatis`;
use `mybatis`;

create table `user`(
id int not null,
name varchar(30) default null,
pwd varchar(30) default null,
primary key(`id`)
)  ENGINE=INNODB default CHARSET=utf8;

insert into `user`(`id`, `name`, `pwd`)
values(1, 'qwer', '123456'),
(2, 'asdf', '123456'),
(3, 'zxcv', '123456');

新建項目

  • ??1.新建一個普通的maven項目
  • ??2.刪除src目錄
  • ??3.導入maven依賴
<dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</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>
    </dependencies>

1.2創(chuàng)建一個模塊

  • 編寫mybatis 核心文件
<?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>
    <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/Mybatis?useSSL=true&amp;useUnicode=true&amp;charterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="root123"/>
            </dataSource>
        </environment>
    </environments>
</configuration>
  • 編寫mybatis 工具類
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static{//初始加載
        try {
            //獲取SqlSessionFactory對象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //有了 SqlSessionFactory,可以從中獲得 SqlSession 的實例蛤袒。
    // SqlSession 提供了在數(shù)據(jù)庫執(zhí)行 SQL 命令所需的所有方法。openSession
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
 }

1.3 編寫代碼

  • 實現(xiàn)類
public class User {
    private int id;
    private String name;
    private String pwd;
    public User() {
    }
    public User(int id, String name, String pwd) {

        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
}
  • dao接口
public interface UserDao {
    List<User> getUserList();
}
  • 接口實現(xiàn) 由DaoImpl轉(zhuǎn)換為了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">
<mapper namespace="com.beibei.dao.UserDao">

    <select id="getUserList" resultType="com.beibei.pojo.User">
        select * from mybatis.user;
    </select>
</mapper>

1.4測試

Junit測試

public class UserDemoTest {
    @Test
    public void test(){
        //獲得sqlsession對象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //執(zhí)行sql
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        List<User> userList = userDao.getUserList();
        for (User user :userList) {
            System.out.println(user);
        }
        //關閉sqlsession
        sqlSession.close();

    }
}

注意點:
錯誤一:org.apache.ibatis.binding.BindingException: Type interface com.beibei.dao.UserDao is not known to the MapperRegistry.
MapperRegistry是什么慈俯?
解決方法:mybatis配置文件中添加

<!--每一個mapper.xml都需要在Mybatis核心配置文件中注冊  斜桿不是.-->
    <mappers>
        <mapper resource="com/beibei/dao/UserMapper.xml"/>
    </mappers>

錯誤二:
java.lang.ExceptionInInitializerError
Could not find resource com.beibei.dao.UserMapper.xml
解決方法:內(nèi)部pom.xml添加

<!--解決資源放在內(nèi)部到逊,導出失敗的問題-->
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

生命周期和作用域

SqlSessionFactoryBuilder->sqlSessionFactory->SqlSession
SqlSessionFactoryBuilder 實例的最佳作用域是方法作用域(也就是局部方法變量):不占用過多資源
SqlSessionFactory 最佳作用域是應用作用域:等同于連接池過多創(chuàng)建影響性能吮便,單例模式
SqlSession 實例不是線程安全的,將 SqlSession 放在一個和 HTTP 請求相似的作用域中镜粤,每次收到 HTTP 請求,就可以打開一個SqlSession,返回一個響應后屏轰,就關閉它僚匆。sqlSession.close();

2. CRUD

??1.namespace

namespace中的包名要和Dao/mapper接口的包名保持一致。

??2.select/insert/update/delete

選擇同规,查詢語句:

  • id:對應namespace方法名循狰;
  • resultType:Sql語句執(zhí)行返回值窟社!
  • parameterType:參數(shù)類型

1.編寫接口

public interface UserDao {
    List<User> getUserList();
    User getUserByID(int id);
    int addUser(User user);
    int updateUser(User user);
    int deleteUser(int id);
}

2.編寫mapper中的sql語句

<select id="getUserList" resultType="com.beibei.pojo.User">
        select * from mybatis.user;
    </select>

    <select id="getUserByID" resultType="com.beibei.pojo.User" parameterType="int">
        select * from mybatis.user where id = #{id};
    </select>
    
    <insert id="addUser" parameterType="com.beibei.pojo.User">
        insert into mybatis.user(id, name, pwd) values (#{id}, #{name}, #{pwd});
    </insert>

    <update id="updateUser" parameterType="com.beibei.pojo.User">
        update mybatis.user
        set name=#{name},
            pwd=#{pwd}
        where id=#{id};
    </update>

    <delete id="deleteUser" parameterType="id">
        delete from mybatis.user where id = #{id}
    </delete>

3.測試 ==注意事務的提交==

@Test
    public void testSelectbyID(){
        //獲得sqlsession對象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //執(zhí)行sql
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        User user = userDao.getUserByID(1);
            System.out.println(user);
        //關閉sqlsession
        sqlSession.close();
    }

    @Test
    public void testAddUser(){
        //獲得sqlsession對象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //執(zhí)行sql
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        int res = userDao.addUser(new User(4, "hanhan", "123456"));
        System.out.println(res);
        //提交事務
        sqlSession.commit();
        //關閉sqlsession
        sqlSession.close();

    }

    @Test
    public void testUpdateUser(){
        //獲得sqlsession對象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //執(zhí)行sql
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        int res = userDao.updateUser(new User(4, "hehe", "123123"));
        System.out.println(res);
        //提交事務
        sqlSession.commit();
        //關閉sqlsession
        sqlSession.close();

    }
    @Test
    public void testDeleteUser(){
        //獲得sqlsession對象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //執(zhí)行sql
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        int res = userDao.deleteUser(4);
        System.out.println(res);
        //提交事務
        sqlSession.commit();
        //關閉sqlsession
        sqlSession.close();
    }

4.Map妙用

對于字段過多的情況,由于pojo對象的構造方法難以分屬性創(chuàng)建構造方法绪钥,在全屬性構造方法下就必須傳所有參數(shù)灿里,可以使用Map規(guī)避這個問題,只需傳指定參數(shù)即可程腹。

dao:

int updateUserByMap(Map<String, Object> map);

daomapper:

<update id="updateUserByMap" parameterType="map">
        update mybatis.user
        set name=#{username}
        where id=#{id};
    </update>

test:

@Test
    public void testUpdateUserByMap(){
        //獲得sqlsession對象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao User = sqlSession.getMapper(UserDao.class);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("id", 4);
        map.put("username", "meng");
        int i = User.updateUserByMap(map);
        System.out.println(i);
        sqlSession.commit();
        sqlSession.close();
    }

5.模糊查詢

1.Java代碼執(zhí)行的時候匣吊,傳遞通配符%%

List<User> userlist = mapper.getUserLike("%李%");

2.在sql中拼接使用通配符

select * from mybatis.user where name like "%"#{value}"%";

3.配置解析

1.核心配置文件

mybatis-config.xml

properties(屬性)
settings(設置)
typeAliases(類型別名)
typeHandlers(類型處理器)
objectFactory(對象工廠)
plugins(插件)
environments(環(huán)境配置)
    environment(環(huán)境變量)
        transactionManager(事務管理器)
        dataSource(數(shù)據(jù)源)
databaseIdProvider(數(shù)據(jù)庫廠商標識)
mappers(映射器)
  • environments(環(huán)境配置)
    盡管可以配置多個環(huán)境,但每個 SqlSessionFactory 實例只能選擇一種環(huán)境寸潦。
<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
      <property name="..." value="..."/>
    </transactionManager>
    <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>
  1. 默認使用的環(huán)境 ID(比如:default="development")色鸳。
  2. 每個 environment 元素定義的環(huán)境 ID(比如:id="development")。
  3. 事務管理器的配置(比如:type="JDBC")甸祭。
    • 存在JDBC和MANAGED 兩者缕碎,MANAGED一般不用
  4. 數(shù)據(jù)源的配置(比如:type="POOLED")
    • UNPOOLED 無連接池,性能依賴于數(shù)據(jù)庫
    • POOLED 存在連接池池户,減少連接響應時間咏雌,可進一步配置
    • JNDI EJB 或應用服務器這類容器中使用

2.properties(屬性)

通過properties來實現(xiàn)配置文件引用
編寫db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/Mybatis?useSSL=true&useUnicode=true&charterEncoding=UTF-8
username=root
password=root123

mybatis-config.xml中進行引用

<properties resource="db.properties"/>

3.類型別名(typeAliases)

類型別名可為 Java 類型設置一個縮寫名字。 它僅用于 XML 配置校焦,意在降低冗余的全限定類名書寫赊抖。

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
  <typeAlias alias="Comment" type="domain.blog.Comment"/>
  <typeAlias alias="Post" type="domain.blog.Post"/>
  <typeAlias alias="Section" type="domain.blog.Section"/>
  <typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

若有注解,則別名為其注解值寨典。

@Alias("author")
public class Author {
    ...
}

4.settings(設置)

核心配置:
cacheEnabled:全局性地開啟或關閉所有映射器配置文件中已配置的任何緩存氛雪。默認true
lazyLoadingEnabled: 延遲加載的全局開關。當開啟時耸成,所有關聯(lián)對象都會延遲加載报亩。 特定關聯(lián)關系中可通過設置 fetchType 屬性來覆蓋該項的開關狀態(tài)。默認false
logImpl:指定 MyBatis 所用日志的具體實現(xiàn)井氢,未指定時將自動查找弦追。
完整的配置元素:

<settings>
  <setting name="cacheEnabled" value="true"/>
  <setting name="lazyLoadingEnabled" value="true"/>
  <setting name="multipleResultSetsEnabled" value="true"/>
  <setting name="useColumnLabel" value="true"/>
  <setting name="useGeneratedKeys" value="false"/>
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
  <setting name="defaultExecutorType" value="SIMPLE"/>
  <setting name="defaultStatementTimeout" value="25"/>
  <setting name="defaultFetchSize" value="100"/>
  <setting name="safeRowBoundsEnabled" value="false"/>
  <setting name="mapUnderscoreToCamelCase" value="false"/>
  <setting name="localCacheScope" value="SESSION"/>
  <setting name="jdbcTypeForNull" value="OTHER"/>
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

5.其他配置,基本使用不到

  • 類型處理器(typeHandlers)
  • objectFactory(對象工廠)
  • plugins(插件)

6.其他配置花竞,基本使用不到

MapperRegistry:注冊綁定Mapper文件
方式一:

<!--每一個mapper.xml都需要在Mybatis核心配置文件中注冊-->
    <mappers>
        <mapper resource="com/beibei/dao/UserMapper.xml"/>
    </mappers>

方式二:使用class文件綁定注冊

<mappers>
        <mapper class="com.beibei.dao.UserDao"/>
    </mappers>

注意點:
?接口和Mapper.xml文件名稱必須一致
?接口和Mapper.xml文件必須在一個包下

方式三:通過包引入

<mappers>
        <package name="com.beibei.daoo"/>
 </mappers>

注意點:
?接口和Mapper.xml文件名稱必須一致
?接口和Mapper.xml文件必須在一個包下

7.ResultMap結果映射集

當pojo對象與數(shù)據(jù)庫對象字段名稱不相同時劲件,無法正確查詢結果,此時需要使用ResultMap 進行映射

<resultMap id="UserMap" type="com.beibei.pojo.User">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="pwd" column="pasword"/>
</resultMap>
    
<select id="getUserByID" resultMap="UserMap">
        select * from mybatis.user where id = #{id};
</select>

不進行resultType返回约急,使用resultMap進行對象返回
property是數(shù)據(jù)庫字段名
column是pojo屬性

4.日志

如果數(shù)據(jù)庫操作出現(xiàn)異常零远,需要通過日志進行更方便的排錯
在mybatis-config.xml中存在settings進行日志配置
logImpl 指定 MyBatis所用日志的具體實現(xiàn),未指定時將自動查找厌蔽。
核心2種牵辣,STDOUT_LOGGING 和常用的 LOG4J

4.1日志工廠

STDOUT_LOGGING標準的日志工廠實現(xiàn),無需添加外部包奴饮,配置好可直接使用
配置項:

<!--settings放在properties和environments之間-->
    <!--標準的日志工廠實現(xiàn)-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

輸出結果:

Opening JDBC Connection
Created connection 156545103.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@954b04f]
==>  Preparing: select * from mybatis.user where id = ?; 
==> Parameters: 1(Integer)
<==    Columns: id, name, pwd
<==        Row: 1, qwer, 123456
<==      Total: 1
User{id=1, name='qwer', password='123456'}
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@954b04f]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@954b04f]
Returned connection 156545103 to pool.

4.2log4j

優(yōu)點:

  • 可以通過一個配置文件來靈活地進行配置服猪,而不需要修改應用的代碼
  • 日志信息輸送的目的地是控制臺供填、文件、GUI組件罢猪,甚至是套接口服務器近她、NT的事件記錄器、UNIX Syslog守護進程等
  1. 導入log4j
<dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
</dependency>
  1. resources下編寫log4j.properties
    當前配置為輸出到文件和控制臺
### 配置根 ###
#日志信息輸出到console和file下
log4j.rootLogger = debug,console,file

### 設置輸出sql的級別膳帕,其中l(wèi)ogger后面的內(nèi)容全部為jar包中所包含的包名 ###
log4j.logger.org.apache=dubug
log4j.logger.java.sql.Connection=dubug
log4j.logger.java.sql.Statement=dubug
log4j.logger.java.sql.PreparedStatement=dubug
log4j.logger.java.sql.ResultSet=dubug

### 配置輸出到控制臺 ###
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern =  %d{ABSOLUTE} %5p %c{1}:%L - %m%n

### 配置輸出到文件 ###
log4j.appender.file = org.apache.log4j.FileAppender
log4j.appender.file.File = logs/log.log
log4j.appender.file.Append = true
log4j.appender.file.Threshold = DEBUG
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

3.配置log4j為mybatis日志實現(xiàn)

<!--settings放在properties和environments之間-->
    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>

4.測試運行

19:31:52,373 DEBUG LogFactory:105 - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
19:31:52,376 DEBUG LogFactory:105 - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
19:31:52,414 DEBUG PooledDataSource:353 - PooledDataSource forcefully closed/removed all connections.
19:31:52,414 DEBUG PooledDataSource:353 - PooledDataSource forcefully closed/removed all connections.
19:31:52,415 DEBUG PooledDataSource:353 - PooledDataSource forcefully closed/removed all connections.
19:31:52,415 DEBUG PooledDataSource:353 - PooledDataSource forcefully closed/removed all connections.
19:31:52,563 DEBUG JdbcTransaction:136 - Opening JDBC Connection
19:31:52,868 DEBUG PooledDataSource:424 - Created connection 793315160.
19:31:52,868 DEBUG JdbcTransaction:100 - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@2f490758]
19:31:52,875 DEBUG getUserList:143 - ==>  Preparing: select * from mybatis.user; 
19:31:52,920 DEBUG getUserList:143 - ==> Parameters: 
19:31:52,952 DEBUG getUserList:143 - <==      Total: 4
User{id=1, name='qwer', password='123456'}
User{id=2, name='asdf', password='123456'}
User{id=3, name='zxcv', password='123456'}
User{id=4, name='meng', password='123123'}
19:31:52,955 DEBUG JdbcTransaction:122 - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@2f490758]
19:31:52,961 DEBUG JdbcTransaction:90 - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@2f490758]
19:31:52,961 DEBUG PooledDataSource:381 - Returned connection 793315160 to pool.

5.log4j項目使用
使用類中引入
import org.apache.log4j.Logger;
具體測試使用

static Logger logger = Logger.getLogger(UserDemoTest.class);
    @Test
    public void  testLog4j(){
        logger.info("info: testLog4j");
        logger.debug("debug: testLog4j");
        logger.error("error: testLog4j");
    }

可以在輸出文件logs.log看差異

[ INFO ] - 2020-08-30 19:46:07 info: testLog4j
[ DEBUG ] - 2020-08-30 19:46:07 debug: testLog4j
[ ERROR ] - 2020-08-30 19:46:07 error: testLog4j

5.分頁實現(xiàn)

為什么需要分頁粘捎?

  • 減少數(shù)據(jù)處理量

5.1 limit 分頁

limit語法:

mysql> SELECT * FROM table LIMIT 5,10; // 檢索記錄行 6-15
//為了檢索從某一個偏移量到記錄集的結束所有的記錄行,可以指定第二個參數(shù)為 -1: 
mysql> SELECT * FROM table LIMIT 95,-1; // 檢索記錄行 96-last.
//如果只給定一個參數(shù)危彩,它表示返回最大的記錄行數(shù)目: 
mysql> SELECT * FROM table LIMIT 5; //檢索前 5 個記錄行
//換句話說攒磨,LIMIT n 等價于 LIMIT 0,n。

測試:
創(chuàng)建接口:

List<User> getUserListByLimit(Map<String, Object> map);

mapper:

<resultMap id="UserMap" type="com.beibei.pojo.User">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <result property="pwd" column="pasword"/>
</resultMap>

<select id="getUserListByLimit" parameterType="map" resultMap="UserMap">
    select * from mybatis.user limit #{startIndex}, #{pageSize};
</select>

測試調(diào)用:

@Test
    public void testSelectByLimit(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao userdao = sqlSession.getMapper(UserDao.class);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("startIndex", 0);
        map.put("pageSize", 2);

        List<User> userList = userdao.getUserListByLimit(map);
        for (User user:userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }

5.2.RowBounds 分頁

不再使用sql實現(xiàn)分頁汤徽,通過mybatis官方方法實現(xiàn)(不推薦)

接口:

List<User> getUserListByRowBounds();

mapper.xml

<select id="getUserListByRowBounds" resultMap="UserMap">
        select * from mybatis.user;
    </select>   

測試腳本
@Test
public void testSelectByRowBounds(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
RowBounds rowBounds = new RowBounds(1,2 );
List<User> userList = sqlSession.selectList("com.beibei.dao.UserDao.getUserListByRowBounds", null, rowBounds);
for (User user: userList) {
System.out.println(user);
}
sqlSession.close();
}

5.3 其他插件方式

Mysql分頁處理(PageHelper)

6 使用注解開發(fā)

**面向接口編程 **

  • 解耦
  • 定義(規(guī)范娩缰,約束)與實現(xiàn)(名實分離的原則)的分離。
  • 接口的本身反映了系統(tǒng)設計人員對系統(tǒng)的抽象理解

6.1使用注解開發(fā)

1.注解在接口上實現(xiàn)

    @Select("select * from mybatis.user")
    List<User> getUsers();

2.需要在核心配置中綁定接口

<!--mapper 綁定注解接口-->
<mappers>
    <mapper class="beibei.dao.UserDao"/>
</mappers>

3.測試

@Test
public void test(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);
    List<User> userList = mapper.getUsers();
    for (User user: userList ) {
        System.out.println(user);
    }
    sqlSession.close();
    
}

本質(zhì):反射來獲取注解信息實現(xiàn)
底層:動態(tài)代理

6.2 注解開發(fā)CRUD
6.2.1 自動提交事務

public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession(true);//自動提交事務
    }

6.2.2 編寫接口

@Insert("insert into mybatis.user(id, name, pwd) values(#{id}, #{name}, #{pwd})")
int addUser(@Param("id") int id, @Param("name") String name, @Param("pwd") String password);

@Update("update mybatis.user set name=#{name} where id = #{id}")
int updateUser(@Param("id") int id,  @Param("name") String name);

6.2.3 增加測試類

@Test
public void testAddUser(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);
    int i = mapper.addUser(5, "qwer", "123321");
    System.out.println(i);
}

@Test
public void testUpdateUser(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);
    int i = mapper.updateUser(5, "asdf");
    System.out.println(i);
}

6.3 #{} 和${} 區(qū)別

{}是預編譯處理谒府,對應JBDC中的PreparedStatement拼坎,可以防止依賴注入。

${}是字符串替換完疫。不能防止依賴注入

7.Lombok

不用再getter setter 構造 toString ,注解即可完成
1.idea安裝插件
2.導入依賴

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    <scope>provided</scope>
</dependency>

3.使用:

@ToString
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class User {
    private int id;
    private String name;
    private int age;
    private String birth;
    private Date birthday;
}

@Data:生成無參 get set toString equeals hashcode
@AllArgsConstructor:生成全參
@NoArgsConstructor:生成無參

7 復雜查詢

7.1環(huán)境搭建

1.導入lombok
2.新建實體類Teacher泰鸡、Student
3.建立Mapper接口
4.建立Mapper.xml文件
5.核心配置文件中綁定注冊的Mapper接口或文件
6.測試查詢是否成功

7.2 多對一,多表查詢

方式一:按照查詢嵌套處理
核心mapper配置如下

<select id="getAllStudent" resultMap="student-teacher">
    select * from mybatis.student;
</select>

<resultMap id="student-teacher" type="com.beibei.pojo.Student">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <!--查詢結果映射到對應的子查詢條件中-->
    <association property="teacher" column="tid" javaType="com.beibei.pojo.Teacher" select="getTeacher"/>
</resultMap>

<select id="getTeacher" resultType="com.beibei.pojo.Teacher">
    select * from mybatis.teacher where id = #{id};
</select>

方式二:按結果嵌套查詢

<select id="getAllStudent2" resultMap="student-teacher2">
    select s.id sid, s.name sname,t.name tname  from student s, teacher t where t.id = s.tid;
</select>

<resultMap id="student-teacher2" type="com.beibei.pojo.Student">
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
    <!--查詢結果映射到對應的子查詢條件中-->
    <association property="teacher" javaType="com.beibei.pojo.Teacher">
        <result property="name" column="tname"/>
    </association>
</resultMap>

7.3 一對多壳鹤,集合查詢

<select id="getTeacherbyid" resultMap="teacher-student">
    select t.id tid, t.name tname, s.id sid, s.name sname 
    from student s, teacher t 
    where t.id = s.tid and t.id = #{tid};
</select>

<resultMap id="teacher-student" type="com.beibei.pojo.Teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    <!--javatype指定屬性的類型盛龄,集合中的泛型信息,使用oftype獲取-->
    <collection property="students" ofType="com.beibei.pojo.Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    </collection>
</resultMap>

8 動態(tài)sql

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

數(shù)據(jù)庫搭建

CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT '博客id',
`title` VARCHAR(100) NOT NULL COMMENT '博客標題',
`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
`create_time` DATETIME NOT NULL COMMENT '創(chuàng)建時間',
`views` INT(30) NOT NULL COMMENT '瀏覽量',
primary key(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;

pojo對象

@Data
public class Blog {
    private String id;
    private String title;
    private String author;
    private Date createTime;
    private int views;
}

if判斷動態(tài)語句

mapper

<insert id="addBlog" parameterType="com.beibei.pojo.Blog">
    insert into mybatis.blog(id, title, author, create_time, views)
    values (#{id}, #{title}, #{author}, #{createTime}, #{views});
</insert>

<select id="queryBlogIF" parameterType="map" resultType="com.beibei.pojo.Blog">
    select * from mybatis.blog where 1=1
    <if test="title != null">
        and title = #{title}
    </if>

    <if test="author != null">
        and author = #{author}
    </if>
</select>

測試

@org.junit.Test
public void testAddBlog(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    Blog blog = new Blog();
    blog.setAuthor("QWER");
    blog.setCreateTime(new Date());
    blog.setTitle("QWEQWRT");
    blog.setViews(6213);
    blog.setId(IDutils.getIdrandom());
    int i = mapper.addBlog(blog);
    System.out.println(i);
    sqlSession.commit();
    sqlSession.close();
}
@org.junit.Test
public void testQueryBlogIF(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    Map map = new HashMap();
    map.put("author","QWER");
    List<Blog> blogs = mapper.queryBlogIF(map);
    for (Blog blog : blogs) {
        System.out.println(blog.toString());
    }
 //   sqlSession.commit();
    sqlSession.close();
}

choose(when otherwise)選擇動態(tài)語句

和java的switch效果相同
mapper:

<select id="queryBlogChoose" parameterType="map" resultType="com.beibei.pojo.Blog">
    select * from mybatis.blog where 1=1
   <choose>
       <when test="title != null">
           and title = #{title}
       </when>
       
       <when test="title != null and author != null">
           and author = #{author}
       </when>

       <otherwise>
          and views > 100
       </otherwise>
   </choose>
</select>

test:

@org.junit.Test
public void testQueryBlogChoose(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    Map map = new HashMap();
    map.put("author","QWER");
    map.put("title", "QWEQWRT");
    List<Blog> blogs = mapper.queryBlogIF(map);
    for (Blog blog : blogs) {
        System.out.println(blog.toString());
    }
    //   sqlSession.commit();
    sqlSession.close();
}

trim (where, set)

where 是取消where 1=1 使用的芳誓,update中可能使用
trim 則是優(yōu)化多于的and or 余舶,等元素的
==set== 有使用的必要,優(yōu)化update中可能存在的多于","
進行set相關的測試

<update id="updateBlogSet"  parameterType="map">
    update mybatis.blog
    <set>
        <if test="author != null">author = #{author},</if>
        <!-- 大于小于注意要轉(zhuǎn)換,和尾巴的逗號 -->
        <if test="views &gt;= 1000">views = views+1000,</if>
    </set>
    where 1= 1 and author = "pgm"
</update>

測試:

@org.junit.Test
public void testUpdateBlogSet(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    Map map = new HashMap();
    map.put("author","darmon");
    map.put("title", "QWEQWRT");
    int i= mapper.updateBlogSet(map);
        System.out.println(i);
      sqlSession.commit();
    sqlSession.close();
}

foreach 集合類條件動態(tài)語句

你可以將任何可迭代對象(如 List锹淌、Set 等)欧芽、Map 對象或者數(shù)組對象作為集合參數(shù)傳遞給 foreach。當使用可迭代對象或者數(shù)組時葛圃,index 是當前迭代的序號item 的值是本次迭代獲取到的元素憎妙。==當使用 Map 對象(或者 Map.Entry 對象的集合)時库正,index 是鍵,item 是值==
mapper

<select id="queryBlogIn" parameterType="map" resultType="com.beibei.pojo.Blog">
    select * from mybatis.blog
    where 1=1 and author in
    <foreach collection="authors" item="author" index="index"
     open="(" separator="," close=")">
        #{author}
    </foreach>
</select>

測試用例

@org.junit.Test
public void testQueryBlogIn(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    Map map = new HashMap();
    ArrayList<String> authors = new ArrayList<String>();
    authors.add("pgm");
    authors.add("darmon");
    map.put("authors",authors);
    List<Blog> blogs = mapper.queryBlogIn(map);
    for (Blog blog : blogs) {
        System.out.println(blog.toString());
    }
    sqlSession.commit();
    sqlSession.close();
}

9.緩存機制

為了提升查詢效率厘唾,引入了緩存機制
mybatis緩存共定義了2級緩存

一級緩存(本地緩存):
  • 默認情況開啟
  • 作用于Sqlsession級別(sqlsession.close關閉便關閉)
  • 修改數(shù)據(jù)后緩存失效(全刷新褥符,失效)
  • sqlsession.clearCache();//清理緩存
二級緩存:
  • namespace級別緩存(又叫mapper級別,任意訪問mapper.xml的文件都能使用)
  • 主配置文件中必須開啟緩存設置(默認開啟)
<setting name="cacheEnabled" value="true"/>
  • 在mapper.xml中添加<cache/>既開啟二級緩存
  • 緩存設置(FIFO 緩存(先進先出)抚垃,每隔 60 秒刷新喷楣,最多可以存儲結果對象或列表的 512 個引用趟大,而且返回的對象被認為是只讀的)
  • 默認使用LRU算法機制(最近最少使用)
 <cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>
  • 緩存策略包含
LRU – 最近最少使用:移除最長時間不被使用的對象。
FIFO – 先進先出:按對象進入緩存的順序來移除它們铣焊。
SOFT – 軟引用:基于垃圾回收器狀態(tài)和軟引用規(guī)則移除對象逊朽。
WEAK – 弱引用:更積極地基于垃圾收集器狀態(tài)和弱引用規(guī)則移除對象

存在多級緩存時,查詢調(diào)用順序是== 優(yōu)先二級緩存 ==曲伊,==其次一級緩存==叽讳,==最后查數(shù)據(jù)庫==
Mybatis執(zhí)行流程

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市坟募,隨后出現(xiàn)的幾起案子岛蚤,更是在濱河造成了極大的恐慌,老刑警劉巖懈糯,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涤妒,死亡現(xiàn)場離奇詭異,居然都是意外死亡赚哗,警方通過查閱死者的電腦和手機她紫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蜂奸,“玉大人犁苏,你說我怎么就攤上這事±┧” “怎么了围详?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長祖屏。 經(jīng)常有香客問我助赞,道長,這世上最難降的妖魔是什么袁勺? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任雹食,我火速辦了婚禮,結果婚禮上期丰,老公的妹妹穿的比我還像新娘群叶。我一直安慰自己,他們只是感情好钝荡,可當我...
    茶點故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布街立。 她就那樣靜靜地躺著,像睡著了一般埠通。 火紅的嫁衣襯著肌膚如雪赎离。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天端辱,我揣著相機與錄音梁剔,去河邊找鬼虽画。 笑死,一個胖子當著我的面吹牛荣病,可吹牛的內(nèi)容都是我干的码撰。 我是一名探鬼主播,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼众雷,長吁一口氣:“原來是場噩夢啊……” “哼灸拍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起砾省,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤鸡岗,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后编兄,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體轩性,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年狠鸳,在試婚紗的時候發(fā)現(xiàn)自己被綠了揣苏。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,742評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡件舵,死狀恐怖卸察,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情铅祸,我是刑警寧澤坑质,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站临梗,受9級特大地震影響涡扼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜盟庞,卻給世界環(huán)境...
    茶點故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一吃沪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧什猖,春花似錦票彪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至荤傲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間颈渊,已是汗流浹背遂黍。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工终佛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人雾家。 一個月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓铃彰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親芯咧。 傳聞我的和親對象是個殘疾皇子牙捉,可洞房花燭夜當晚...
    茶點故事閱讀 45,747評論 2 361