Mybatis


Mybatis

簡介:

MyBatis 是一款優秀的持久層框架,它支持定制化 SQL、存儲過程以及高級映射。

MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。

MyBatis 可以使用簡單的 XML 或注解來配置和映射原生信息,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對象)映射成數據庫中的記錄

1.JDBC訪問數據庫的步驟:

1.加載數據庫驅動 Driver

2.獲取連接 Connection

3.獲取sql執行器 Statement,PrepareStatement

4.執行sql,得到結果集 ResultSet

5.javaBean映射操作

6.關閉連接

內部組織結構:

核心原理:

2.核心對象:

SqlSessionFactoryBuilder

用來加載配置文件,調用build方法創建SqlSessionFactory對象

SqlSessionFactoryBuilder是通過xml配置文件或者configuration類的實例去構造這個對象。然后調用build()方法去構造SqlSessionFactory對象。

用過即丟,其生命周期只存在於方法體內
可重用其來創建多個SqlSessionFactory實例
負責構建SqlSessionFactory,並提供多個build方法的重載

SqlSessionFactory

SqlSessionFactory對象調用openSession方法獲取SqlSession對象

SqlSessionFactory是我們MyBatis整個應用程序的中心;

整個程序都是以SqlSessionFactory的實例為核心的,

使用SqlSessionFactory對象的openSession()方法來獲取SqlSession對象,

用SqlSession對象去操作數據庫

因為SqlSession里面包含了以數據庫為背景所有執行sql操作的方法。

SqlSession

包含了執行sql所需的所有方法
對應一次數據庫會話,會話結束必須關閉
線程級別,不能共享

在SqlSession里可以執行多次SQL語句,但一旦關閉了SqlSession就需要重新創建。

SqlSession實例不能被共享,也不是線程安全的。所以其最佳作用域是reqeust作用域內或者方法體內的作用域內。

3.Mybatis配置形式流程:

3.1配置依賴

<!--?xml version="1.0" encoding="UTF-8"?-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelversion>4.0.0</modelversion>
    
    <groupid>com.iweb</groupid>
    <artifactid>mybatis</artifactid>
    <version>1.0-SNAPSHOT</version>
    
<dependencies>
    <dependency>
        <groupid>mysql</groupid>
        <artifactid>mysql-connector-java</artifactid>
        <version>5.1.39</version>
    </dependency>
    <dependency>
        <groupid>c3p0</groupid>
        <artifactid>c3p0</artifactid>
        <version>0.9.1.2</version>
    </dependency>
    <!--mybatis依賴-->
    <dependency>
        <groupid>org.mybatis</groupid>
        <artifactid>mybatis</artifactid>
        <version>3.2.8</version>
    </dependency>
    <dependency>
        <groupid>junit</groupid>
        <artifactid>junit</artifactid>
        <version>4.11</version>
    </dependency>
</dependencies>

</project>

3.2創建實體類

package com.iweb.entity;

/**
 **/
public class User {
    private Integer id;
    private String name;
    private Integer 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;
}

@Override
public String toString() {
    return "User{" +
            "id=" + id +
            ", name='" + name + '\'' +
            ", age=" + age +
            '}';
	}
}

3.3編寫核心配置文件sqlMapConfig.xml

需要配置環境environment,

事務管理器transactionManager,

數據源POOLED,

引入映射文件,請看第五步

<!--?xml version="1.0" encoding="UTF-8" ?-->

<!--configuration核心配置標簽-->
<configuration>

    <!--environments環境配置-->
    <environments default="mysql"><!--環境名任意取,要和下面的對應即可-->
        <environment id="mysql">
            <!--transactionManager事務管理器,type=JDBC使用jdbc管理事務-->
            <transactionmanager type="JDBC">
            <!-- 配置數據源 type="POOLED"使用mybatis自帶的連接池-->
            <datasource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver">
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis">
                <property name="username" value="root">
                <property name="password" value="123456">
            </property></property></property></property></datasource>
        </transactionmanager></environment>
    </environments>
</configuration>

3.4編寫映射文件,編寫sql

這個配置文件寫在resource目錄中

namespace 其實就是實現對應的接口,和jdbc的接口實現類相似

select標簽中的id,就相當於jdbc實現類的方法名;resultType 返回的javaBean類型

<!--?xml version="1.0" encoding="UTF-8" ?-->


<!--namespace命名空間,給SqlSession提供可以識別區分不同的命名空間
	這個namespace	其實就是實現對應的接口,和jdbc的接口實現類相似
-->
<mapper namespace="com.iweb.mapper.UserMapper">
    <!--id 唯一定義標識,在同一命名空間下,id不能重復
        resultType 定義執行這條sql語句后,返回的javaBean類型
        select標簽 用來定義查詢語句
    -->
    <select id="getAllUser" resulttype="com.iweb.entity.User">
        select * from user
    </select>
    <!--parameterType 定義參數的類型-->
    <select id="getUserById" parametertype="java.lang.Integer" resulttype="com.iweb.entity.User">
        select * from user where id=#{id}
    </select>
    <!--當接收javaBean對象參數時,#{}在取值時,需和實體中的屬性名相同,且要提供get、set方法-->
    <insert id="addUser" parametertype="com.iweb.entity.User">
        insert into user (username,password,nickname,email,phone,gender,status)
        values (#{username},#{password},#{nickname},#{email},#{phone},#{gender},#{status})
    </insert>

    <insert id="addUser" parametertype="com.iweb.entity.User">
        insert into user (username,password,nickname,email,phone,gender,status)
        values (#{username},#{password},#{nickname},#{email},#{phone},#{gender},#{status})
    </insert>
</mapper>

3.5將映射文件配置到sqlMapConfig.xml中

每一個Mapper.xml都需要在Mybatis核心配置文件中注冊,需要用到mapper標簽

<!--?xml version="1.0" encoding="UTF-8" ?-->

<!--configuration核心配置標簽-->
<configuration>

    <!--environments環境配置-->
    <environments default="mysql"><!--環境名任意取,要和下面的對應即可-->
        <environment id="mysql">
            <!--transactionManager事務管理器,type=JDBC使用jdbc管理事務-->
            <transactionmanager type="JDBC">
            <!-- 配置數據源 type="POOLED"使用mybatis自帶的連接池-->
            <datasource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver">
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis">
                <property name="username" value="root">
                <property name="password" value="123456">
            </property></property></property></property></datasource>
        </transactionmanager></environment>
    </environments>

    <!--導入mapper.xml配置
        配置映射文件
    -->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"></mapper>
        <!--使用class屬性指向需要使用注解的包路徑或類路徑-->
    	<mapper class="com.iweb.mapper.UserMapperAnnotation"></mapper>
    </mappers>
</configuration>

3.6測試

1.獲取mybatis主配置文件,得到一個輸入流

2.創建SqlSessionFactoryBuilder對象

3.通過builder的build方法加載配置文件,創建SqlSessionFactory對象

4.獲取SqlSession對象,支持事務,但不提交

​ factory.openSession(true);設置自動提交事務

測試類其實就三步:

1.獲得一個sqlSession

2.獲取mapper,拿到對應的mapper對象

3.通過mapper對象就可以調用接口中定義的方法

public void test1() throws Exception{
    //1.獲取mybatis主配置文件,得到一個輸入流
    InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");
    //2.創建SqlSessionFactoryBuilder對象
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    //3.通過builder的build方法加載配置文件,創建SqlSessionFactory對象
    SqlSessionFactory factory = builder.build(in);
    //4.獲取SqlSession對象,支持事務,但不提交
    SqlSession session = factory.openSession();
    //factory.openSession(true);//設置自動提交事務

    
    // 里面執行sql語句的select標簽id為getAllUser
    List<object> list = session.selectList("test.getAllUser");
    
    //更多使用自己配置的接口
    UserMapper mapper = session.getMapper("UserMapper.xml");
    User allUser = mapper.getAllUser;
    //test.getAllUser:映射xml中的命名空間test
    System.out.println(list);
}

4.Mybatis注解形式:

4.1創建核心配置文件 sqlMapConfig.xml

<!--?xml version="1.0" encoding="UTF-8" ?-->

<!--configuration核心配置標簽-->
<configuration>

    <!--environments環境配置-->
    <environments default="mysql"><!--環境名任意取,要和下面的對應即可-->
        <environment id="mysql">
            <!--transactionManager事務管理器,type=JDBC使用jdbc管理事務-->
            <transactionmanager type="JDBC">
            <!-- 配置數據源 type="POOLED"使用mybatis自帶的連接池-->
            <datasource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver">
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis">
                <property name="username" value="root">
                <property name="password" value="123456">
            </property></property></property></property></datasource>
        </transactionmanager></environment>
    </environments>

    <!--導入mapper.xml配置
    classpath:找到模塊的resource路徑
    -->
    <mappers>
        <!--使用class屬性指向需要使用注解的包路徑或類路徑-->
        <mapper class="com.iweb.mapper.UserMapperAnnotation"></mapper>
    </mappers>
</configuration>

4.2在mapper接口中使用注解

package com.iweb.mapper;

import com.iweb.entity.User;

import java.util.List;
import java.util.Map;
/**
 * 注解形式mapper
 */
public interface UserMapperAnnotation {
    @Select("select * from user")
    public List<user> getAllUser();

    @Select("select * from user where id=#{id}")
    public User getUserById(Integer id);

    @Delete("delete from user where id=#{id}")
    public void deleteUser(Integer id);
}

4.3配置一個utils工具類,不用重復寫獲得sqlSession對象的代碼

public static <t> T getAnnotationMapper(Class<t> clz){
    InputStream in = null;
    try{
        //1.獲取mybatis主配置文件,得到一個輸入流
        in = Resources.getResourceAsStream("mybatis-Config.xml");
        //2.創建SqlSessionFactoryBuilder對象
        // 通過builder的build方法加載配置文件,創建SqlSessionFactory對象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //3.獲取SqlSession對象
        SqlSession session = factory.openSession(true);
        return session.getMapper(clz);
    }catch (IOException e){
        e.printStackTrace();
    }finally {
        try {
            in.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
    return null;
}

自己寫的工具類:

public class MybatisUtils {
    //獲取SqlSession
    public static SqlSession getSqlSession() throws IOException {
        //獲取文件流
        InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");

        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        SqlSession session = factory.openSession(true);
        return session;
    }
}

注解形式的測試:

@Test
public void test1(){
    UserMapperAnnotation mapper = MybatisUtil.getAnnotationMapper(UserMapperAnnotation.class);
    List<user> allUser = mapper.getAllUser();
    System.out.println(allUser);
}
@Test
public void test2(){
    UserMapperAnnotation mapper = MybatisUtil.getAnnotationMapper(UserMapperAnnotation.class);
    System.out.println(mapper.getUserById(2));
}
@Test
public void test3(){
    UserMapperAnnotation mapper = MybatisUtil.getAnnotationMapper(UserMapperAnnotation.class);
    mapper.deleteUser(2);
}

5.sql中的取值方式:

#{}與${}

{}特點:

會作為sql參數使用,替代掉sql中的?

有預編譯機制,防止sql注入,效率高

字符串類型,日期類型,會自動兩邊拼單引號

insert into user values(null,#{name},55) -->insert into user values(null,'張三',55)
insert into user values(null,${name},55) -->insert into user values(null,張三,55) 
--sql語句錯誤  

${}特點:

會原樣直接拼接到sql上

沒有預編譯機制,不能防止sql注入,效率低

字符串類型,日期類型,不會自動兩邊拼單引號

select * from user order by #{name}--> select * from user order by 'name'//sql錯誤 
select * from user order by ${name}--> select * from user order by name

總結:

通常都使用#{},可以防止sql注入,效率高,但如果傳遞的是列名,表名,關鍵字等必須直接拼接到sql的內容時,使用${},防止自動拼接單引號改變sql語義

6.參數的傳值:

map傳遞參數,直接在sql中取出key即可 parameterType="map"

對象傳遞參數,直接在sq中取出對象的屬性即可 parameterType="Object"

只有一個基本類型參數的情況下,可以直接在sql中取到

多個參數用map,或者注解

6.1單值傳遞

6.2map傳值

當實體類或數據庫中的表字段或參數過多時,考慮使用map傳值。這樣可以不用把所有的字段都寫出來

比如說,數據庫某表中有100個字段,當要修改數據庫表中某一條記錄的某一個字段時,使用map傳值,就只需要寫要改的字段即可。而如果是單值傳遞,就要把所有字段全部寫上。

<insert id="updateUser" parametertype="map">
    <!--此處values其實就是map中的鍵,也是表字段名-->
	insert into user (id,password) values(#{id},#{password})
</insert>

map傳遞參數,直接在sql中取出key即可

@Test
public void test2() throws IOException {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    Map<string, object=""> map = new HashMap<>();
    //put的鍵對應xml中的values的鍵,為了代碼可讀性,還是要求名字相同
    map.put("id","6");
    map.put("password","tihuandemima");
    mapper.updateUser(map);
}

模糊查詢:

1.java代碼執行的時候,傳遞通配符% %

List<user> userList = mapper.getUserList("%李%");

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

<select id="getUserList" resulttype="com.iweb.domain.User" select="" *="" from="" user="" where="" name="" like="" "%"#{name}"%"="" <="">

7.配置優化解析

7.1環境配置:

mybatis可以配置成適應多種環境

注意:盡管可以配置多個環境,但每個SqlSessionFactory實例只能選擇一種環境

mybatis默認的事務管理器就是jdbc,連接池:POOLED

7.2屬性:properties

通過properties屬性來實現引用配置文件

這些屬性都是可以通過外部配置動態替換的。

編寫一個配置文件:db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf-8
username=root
password=123456

在核心配置文件中引入

properties標簽必須寫在最上面

<!--?xml version="1.0" encoding="UTF-8" ?-->
        
        <!--configuration核心配置標簽-->

<!--引入外部配置文件,properties放在resource目錄下-->
    
<!--environments環境配置-->
<!--環境名任意取,要和下面的對應即可-->
    
        <!--transactionManager事務管理器,type=JDBC使用jdbc管理事務-->
        
        <!-- 配置數據源 type="POOLED"使用mybatis自帶的連接池-->
        
            
            
            
            
        
    


7.3別名:typeAliases

放在configuration標簽的第三個位置

類型別名是為java類型設置一個短名字

存在的意義僅在於減少類全名的冗余

3.1給實體類起別名


    

實體類起別名之后就不用寫全類名了,就寫別名

</select>
    select * from user

3.2也可以指定一個包名,mybatis會在包名下搜索需要的javaBean

掃描實體類的包,他默認的別名就是這個類的類名首字母小寫

<typealiases>
    <package name="com.iweb.domain">
</package></typealiases>

區別:

在實體類比較少的時候,使用第一種

當實體類特別多,建議使用第二種

第一種可以diy別名,第二種不行,如果非要改,需要在實體上增加注解@Alias

7.4映射器:mappers

每一個mapper.xml都需要在mybatis核心配置文件中注冊

注冊綁定我們的mapper文件

方式1:resource資源路徑綁定 ——[推薦使用]

<mappers>
	<mapper resource="com/iweb/mapper/UserMapper.xml">
</mapper></mappers>

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

<mappers>
	<mapper class="com.iweb.mapper.Usermapper">
</mapper></mappers>

注意

接口和他的mapper配置文件必須同名

接口和他的mapper配置文件必須在同一個包下

方式3:使用掃描包進行注入綁定

<mappers>
	<package name="com.iweb.mapper">
</package></mappers>

注意

接口和他的mapper配置文件必須同名

接口和他的mapper配置文件必須在同一個包下

7.5生命周期和作用域

生命周期和作用域,是至關重要的,因為錯誤的使用會導致非常嚴重的並發問題

SqlSessionFactoryBuilder:

一旦創建了SqlSessionFactory,就不再需要它了

一般做成員變量

SqlSessionFactory

說白了就是:數據庫連接池

SqlSessionFactory一旦被創建,就會在應用的運行期間一直存在,沒有任何理由丟棄或重新創建。因為丟棄和重新創建都會浪費內存資源

SqlSessionFactory的最佳作用域是application,也就是整個應用中,直到應用關閉

最簡單的使用就是單例模式,保證全局只有一個

SqlSession

連接到連接池的一個請求

SqlSession的實例不是線程安全的,因此不能被共享,所以它的最佳作用域是請求或方法作用域

用完之后需要趕緊關閉,否則資源被占用

一個SqlSessionFactory可以創建多個SqlSession,

每個SQLSession可以獲得多個mapper,

這里的每一個mapper,就代表一個具體的業務

8.解決屬性名和字段名不一致的問題:resultMap

實體類:

public class User {
    private Integer id;
    private String username;
    private String pwd;//將這里的屬性名和數據庫字段名設置不一致
    private String nickname;
}

mapper.xml

<select id="getUserList" resulttype="user">
    select id,username,password from user
</select>

當獲取信息后,由於屬性名和字段名不一致,pwd的值會為空

解決方法:

方式1:起別名

<select id="getUserList" resulttype="user">
    select id,username,password pwd from user
</select>

方式2:resultMap結果集映射

resultMap標簽中

type:就是返回的數據類型

id:給select標簽中的resultMap屬性指定結果集映射

resultMap標簽中的result標簽

column:數據庫表字段名;property:實體類屬性名

<resultmap id="userMap" type="user">
    <!--column:數據庫中字段名。property:實體類中屬性名-->
    <result column="password" property="pwd">
</result></resultmap>

<select id="getUserList" resultmap="userMap">
    select * from user where id=#{id}
</select>

9.日志工廠:

主要用來排錯,把錯誤的信息用日志記錄

在mybatis核心配置文件中配置settings

<settings>
    <!--標准日志工廠實現-->
    <setting name="logImpl" value="STDOUT_LOGGING">
</setting></settings>

log4j:

可以將日志信息傳送到控制台、文件、GUI組件中

可以控制每一條日志的輸出格式,通過一個配置文件來靈活進行配置(log4j.properties)

1.導入log4j依賴

<dependency>
    <groupid>log4j</groupid>
    <artifactid>log4j</artifactid>
    <version>1.2.17</version>
</dependency>

2.log4j.properties(根據具體輸出到哪里而定,網上可搜)

#############
# 輸出到控制台
#############

# log4j.rootLogger日志輸出類別和級別:只輸出不低於該級別的日志信息DEBUG < INFO < WARN < ERROR < FATAL
# WARN:日志級別     CONSOLE:輸出位置自己定義的一個名字       logfile:輸出位置自己定義的一個名字
log4j.rootLogger=WARN,CONSOLE,logfile
# 配置CONSOLE輸出到控制台
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender 
# 配置CONSOLE設置為自定義布局模式
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout 
# 配置CONSOLE日志的輸出格式  [frame] 2019-08-22 22:52:12,000  %r耗費毫秒數 %p日志的優先級 %t線程名 %C所屬類名通常為全類名 %L代碼中的行號 %x線程相關聯的NDC %m日志 %n換行
log4j.appender.CONSOLE.layout.ConversionPattern=[frame] %d{yyyy-MM-dd HH:mm:ss,SSS} - %-4r %-5p [%t] %C:%L %x - %m%n

################
# 輸出到日志文件中
################

# 配置logfile輸出到文件中 文件大小到達指定尺寸的時候產生新的日志文件
log4j.appender.logfile=org.apache.log4j.RollingFileAppender
# 保存編碼格式
log4j.appender.logfile.Encoding=UTF-8
# 輸出文件位置此為項目根目錄下的logs文件夾中
log4j.appender.logfile.File=logs/root.log
# 后綴可以是KB,MB,GB達到該大小后創建新的日志文件
log4j.appender.logfile.MaxFileSize=10MB
# 設置滾定文件的最大值3 指可以產生root.log.1、root.log.2、root.log.3和root.log四個日志文件
log4j.appender.logfile.MaxBackupIndex=3  
# 配置logfile為自定義布局模式
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %F %p %m%n

##########################
# 對不同的類輸出不同的日志文件
##########################

# club.bagedate包下的日志單獨輸出
log4j.logger.club.bagedate=DEBUG,bagedate
# 設置為false該日志信息就不會加入到rootLogger中了
log4j.additivity.club.bagedate=false
# 下面就和上面配置一樣了
log4j.appender.bagedate=org.apache.log4j.RollingFileAppender
log4j.appender.bagedate.Encoding=UTF-8
log4j.appender.bagedate.File=logs/bagedate.log
log4j.appender.bagedate.MaxFileSize=10MB
log4j.appender.bagedate.MaxBackupIndex=3
log4j.appender.bagedate.layout=org.apache.log4j.PatternLayout
log4j.appender.bagedate.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %F %p %m%n

3.在核心配置文件中配置log4j日志的實現

<settings>
    <!--log4j日志工廠實現-->
    <setting name="logImpl" value="LOG4J">
</setting></settings>

簡單使用:

1.在要使用log4j的類中,導入import.org.apache.log4j.Logger;

2.創建日志對象,參數為當前類的class

static Logger logger = Logger.getLogger(xxx.class);

3.日志級別

logger.info("info:");
logger.debug("debug:");
logger.error("error:");

10.分頁

10.1使用limit分頁

語法:select * from xxx表 limit startIndex,pageSize;
select * from user limit 3;//顯示前三條

使用mybatis實現分頁,核心sql

1.接口

List<user> getUserByLimit(Map<string,integer> map);

2.Mapper.xml

<select id="getUserByLimit" parametertype="map" resultmap="UserMap">
	select * from user limit #{startIndex},#{pageSize}
</select>

3.測試

@Test
public void getUserByLimit() throws IOException {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    HashMap<string, integer=""> map = new HashMap<string, integer="">();
    map.put("startIndex",1);
    map.put("pageSize",2);

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

10.2使用分頁插件

pageHelper

11.使用注解開發

11.1基本流程

1.注解在接口上實現(增刪改查)

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

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

<mappers>
	<mapper class="com.iweb.domain.UserMapper">
</mapper></mappers>

本質:反射機制實現

底層流程:

1.Resources獲取加載全局配置文件

//例如:全局配置文件mybatis-config.xml
InputStream in = Resource.getResourceAsStream("mybatis-config.xml");

2.實例化SqlSessionFactoryBuilder

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

3.解析配置文件流XMLConfigBuilder(SqlSessionFactoryBuilder源碼中)

build方法做的事情(3,4步驟)

4.所有的配置信息放在Configuration對象里

5.SqlSessionFactory實例化

(build完之后產生SqlSessionFactory對象)

sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);

6.transaction事務管理

7.創建executor執行器

​ 執行mapper

8.創建sqlSession對象

​ 實現CRUD操作,可能會出現sql問題,事務會回滾,回到步驟6

9.執行成功,提交事務

10.關閉sqlSession

11.2CRUD

1.當方法存在多個參數,所有的參數前必須加上@Param("字段名")這個注解

編寫接口,添加注解

@Select("select * from user where id = #{id} and name = #{張三}")
//此時取的參數對應的是注解Param中的參數名,必須和字段名一致
User getUser(@Param("id") int id,@Param("name") String name);

@Select、@Insert、@Update、@Delete

注意:必須要將接口注冊綁定到核心配置文件中

關於@Param()注解

基本類型或String類型參數,需要加上,引用類型不需要

如果只有一個基本類型,可以忽略,但建議都加上

在sql中引用的就是這里的@Param("xxx")中設定的屬性名,所有要求字段名和屬性名相對應

12.多對一處理

多個學生,對應一個老師

對於學生來說,多個學生,(association)關聯一個老師【多對一】

對應老師來說,一個老師,(collection)有很多學生【一對多】

環境搭建流程:

1.導入lombok,建立實體類

2.建立對應實體類的Mapper接口

3.建立對應Mapper.xml文件

4.在核心配置文件中綁定注冊Mapper接口或文件

5.測試CRUD是否能成功

學生實體類:

@Data
public class Student{
	private int id;
	private String name;
	//學生需要關聯一個老師
	private Teacher teacher;
}

老師實體類:

@Data
public class Teacher{
	private int id;
	private String name;
}

查詢嵌套處理:

比如,有一個學生表,一個老師表,學生和老師通過tid和id進行關聯,

不使用這種形式

select s.id,s.name,t.name from student s,teacher t where s.tid=t.id

而使用嵌套查詢

<!--
     思路:
        1. 查詢所有的學生信息
        2. 根據查詢出來的學生的tid尋找特定的老師 (子查詢)
	由於學生信息里有老師這個對象,所以需要單獨處理
    -->
<select id="getStudent" resultmap="StudentTeacher">
    select * from student
</select>

<resultmap id="StudentTeacher" type="student">
    <result property="id" column="id">
    <result property="name" column="name">
    <!--復雜的屬性,我們需要單獨出來 對象:association 集合:collection
	javaType:由於是一個對象,需要給對象設置類型
	-->
    <collection property="teacher" column="tid" javatype="teacher" select="getTeacher"> <!--這里的select就是嵌套查詢-->
</collection></result></result></resultmap>

<select id="getTeacher" resulttype="teacher">
    select * from teacher where id = #{id}
</select>

按照結果嵌套查詢:

<!--按照結果進行查詢-->
<select id="getStudent2" resultmap="StudentTeacher2">
    select s.id sid , s.name sname, t.name tname
    from student s,teacher t
    where s.tid=t.id
</select>
<!--結果封裝,將查詢出來的列封裝到對象屬性中-->
<resultmap id="StudentTeacher2" type="student">
    <result property="id" column="sid">
    <result property="name" column="sname">
    
    <association property="teacher" javatype="teacher">
        <result property="name" column="tname"></result>
    </association>
</result></result></resultmap>

13.一對多處理

學生實體類:

@Data
public class Student{
	private int id;
	private String name;
	private int tid;
}

老師實體類:

@Data
public class Student{
	private int id;
	private String name;
	//一個老師擁有多個學生
	private List<student> students;
}

按照結果嵌套查詢:

<!--按結果嵌套查詢-->
<select id="getTeacher" resultmap="StudentTeacher">
    SELECT s.id sid, s.name sname,t.name tname,t.id tid FROM student s, teacher t
    WHERE s.tid = t.id AND tid = #{tid}
</select>
<resultmap id="StudentTeacher" type="Teacher">
    <result property="id" column="tid">
    <result property="name" column="tname">
    <!--復雜的屬性,我們需要單獨處理 對象:association 集合:collection
    javaType=""指定屬性的類型!
    集合中的泛型信息,我們使用ofType獲取
    -->
    <collection property="students" oftype="Student">
        <result property="id" column="sid">
        <result property="name" column="sname">
        <result property="tid" column="tid">
    </result></result></result></collection>
</result></result></resultmap>

建議使用結果嵌套查詢

小結:

​ javaTpye:用來指定實體類中屬性的類型

​ ofType:用來指定映射到List或集合中的pojo類型,泛型中的類型

14.動態sql:

​ 也就是sql語句,在sql語句中,執行一些邏輯代碼,比如if,where,choose,when

主要用來解決根據不同條件拼接sql語句,比如拼接時不能忘記添加必要的空格,去掉列表最后一個列名的逗號

14.1 if語句:

​ 固定格式

​ 根據 username 和 sex 來查詢數據。如果username為空,那么將只根據sex來查詢;反之只根據username來查詢

<select id="selectUserByUsernameAndSex" resulttype="user" parametertype="com.iweb.entity.User">
    select * from user where
        
           username=#{username}
        
         
        
           and sex=#{sex}
        
</select>

14.2 if+where 語句:

​ 這個“where”標簽會知道如果它包含的標簽中有返回值的話,它就插入一個‘where關鍵字。此外,如果標簽返回的內容是以AND 或OR 開頭的,則它會剔除掉。

比如說,username !=null不成立,執行的sql語句就會變成select * from user and sex=?

加上where標簽后,會自動將and剔除

<select id="selectUserByUsernameAndSex" resulttype="user" parametertype="com.iweb.entity.User">
    select * from user
    
        
           username=#{username}
        
         
        
           and sex=#{sex}
        
    
</select>

14.3 if+set 語句

​ set會動態前置SET關鍵字,同時也會刪掉無關的逗號

<!-- 根據 id 更新 user 表的數據 -->
<update id="updateUserById" parametertype="com.iweb.entity.User">
    update user u
        <set>
            <if test="username != null and username != ''">
                u.username = #{username},<!--注意此處的,不要忽略了-->
            </if>
            <if test="sex != null and sex != ''">
                u.sex = #{sex}
            </if>
        </set>
     
     where id=#{id}

這樣寫,如果第一個條件 username 為空,那么 sql 語句為:update user u set u.sex=? where id=?

如果第一個條件不為空,那么 sql 語句為:update user u set u.username = ? ,u.sex = ? where id=?

14.4 choose(when,otherwise) 語句

​ 有時候,我們不想用到所有的查詢條件,只想選擇其中的一個,查詢條件有一個滿足即可,使用 choose 標簽可以解決此類問題,類似於 Java 的 switch 語句

<select id="selectUserByChoose" resulttype="com.iweb.entity.User" parametertype="com.iweb.entity.User">
      select * from user
      
          
              
                  id=#{id}
              
              
                  and username=#{username}
              
              
                  and sex=#{sex}
              
          
      
  </select>

也就是說,這里我們有三個條件,id,username,sex,只能選擇一個作為查詢條件

如果 id 不為空,那么查詢語句為:select * from user where id=?

如果 id 為空,那么看username 是否為空,如果不為空,那么語句為 select * from user where username=?;

如果 username 為空,那么查詢語句為 select * from user where sex=?

14.5 trim 語句

​ trim標記是一個格式化的標記,可以完成set或者是where標記的功能。

​ 也就是滿足條件就將對應的條件寫在sql語句中

​ prefix前綴,prefixOverrides前綴覆蓋。

​ suffix后綴,suffixOverrides后綴覆蓋。

<select id="selectUserByUsernameAndSex" resulttype="user" parametertype="com.iweb.entity.User">
        select * from user
        <!-- <where>
            <if test="username != null">
               username=#{username}
            </if>
             
            <if test="username != null">
               and sex=#{sex}
            </if>
        </where>  -->
    <!--上下兩個所展現的sql語句都是同一個-->
        
            
               and username=#{username}
            
            
               and sex=#{sex}
            
        
    </select>

14.6 SQL 片段

​ 有時候可能某個 sql 語句我們用的特別多,為了增加代碼的重用性,簡化代碼,我們需要將這些代碼抽取出來,然后使用時直接調用。

1.使用sql標簽抽取公共的部分

比如:假如我們需要經常根據用戶名和性別來進行聯合查詢,那么我們就把這個代碼抽取出來

<!-- 定義 sql 片段 -->
<sql id="selectUserByUserNameAndSexSQL">
    <if test="username != null and username != ''">
        AND username = #{username}
    </if>
    <if test="sex != null and sex != ''">
        AND sex = #{sex}
    </if>
</sql>

2.在需要使用的地方使用include標簽引用即可

引用 sql 片段

<select id="selectUserByUsernameAndSex" resulttype="user" parametertype="com.iweb.entity.User">
    select * from user
  	<!-- trim 標記是一個格式化的標記,可以完成set或者是where標記的功能 
    	prefix:前綴      
 		 prefixoverride:去掉第一個and或者是or
    -->
    
        <!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace -->
        
        <!-- 在這里還可以引用其他的 sql 片段 -->
    
</select>

注意事項:

1.最好基於單表來定義sql片段,因為多表聯合查詢sql復雜,再引用可能會導致前面的sql語句不匹配

2.不要存在where標簽

14.7 foreach語句

需求:我們需要查詢 user 表中 id 分別為1,2,3的用戶

sql語句:select * from user where id=1 or id=2 or id=3

select * from user where id in (1,2,3)

<!-- 改寫select * from user where id=1 or id=2 or id=3  -->
<select id="selectUserByListId" parametertype="list" resulttype="com.iweb.entity.User">
    select * from user
    
        <!--
            collection:指定輸入對象中的集合屬性
            item:每次遍歷生成的對象
            open:開始遍歷時的拼接字符串
            close:結束時拼接的字符串
            separator:遍歷對象之間需要拼接的字符串
            select * from user where 1=1 and (id=1 or id=2 or id=3)
          -->
        
            id=#{id}
        
    
</select>
<!-- 改寫select * from user where id in(1,2,3) -->
<select id="selectUserByListId" parametertype="list" resulttype="com.iweb.entity.User">
        select * from user
        
            <!--
                collection:指定輸入對象中的集合屬性
                item:每次遍歷生成的對象
                open:開始遍歷時的拼接字符串
                close:結束時拼接的字符串
                separator:遍歷對象之間需要拼接的字符串
                select * from user where 1=1 and id in (1,2,3)
              -->
            
                #{id}
            
        
    </select>

小結:

動態sql就是在拼接sql語句,我們需要保證sql的正確性,按照sql的格式,組合在一起就可以了

建議:先寫出完整的sql,再對應去修改成動態sql實現通用

15.緩存

15.1簡介

1.什么是緩存[Cache]?

存在內存中的臨時數據
將用戶經常查詢的數據放在緩存(內存)中,用戶去查詢數據就不用從磁盤上(關系型數據庫文件)查詢,從緩存中查詢,從而提高查詢效率,解決了高並發系統的性能問題

2.為什么使用緩存?

減少和數據庫的交互次數,減少系統開銷,提高系統效率

3.什么樣的數據可以使用緩存?

經常查詢並且不經常改變的數據 【可以使用緩存】

15.2mybatis緩存

MyBatis系統中默認定義了兩級緩存:一級緩存二級緩存

  • 默認情況下,只有一級緩存開啟(SqlSession級別的緩存,也稱為本地緩存)

  • 二級緩存需要手動開啟和配置,他是基於namespace級別的緩存。

  • 為了提高可擴展性,MyBatis定義了緩存接口Cache。我們可以通過實現Cache接口來定義二級緩存。

15.3一級緩存

一級緩存也叫本地緩存:SqlSession

緩存只在一個事務中有效,即同一個事務中先后執行多次同一個查詢,只在第一次真正查詢數據庫,並將結果緩存,之后的查詢都直接 獲取緩存中的數據,如果是不同的事務,則緩存是隔離的

mybatis一級緩存默認又稱為session級緩存,默認就是開啟狀態,且無法手動關閉

注意,在同一個事務中,如果發生了的修改更新操作(也就是增刪改),一級緩存會失效

緩存失效的情況:

  1. 查詢不同的東西
  2. 增刪改操作,可能會改變原來的數據,所以必定會刷新緩存
  3. 查詢不同的Mapper.xml
  4. 手動清理緩存
SqlSession.clearCache();

15.4二級緩存

mybatis的二級緩存默認是關閉的,需手動開啟,且默認情況下,如果事務沒有提交,二級緩存是失效的。另外,想要被二級緩存緩存的對象必須實現序列化結果

  • 基於namespace級別的緩存,一個名稱空間,對應一個二級緩存
  • 工作機制
    • 一個會話查詢一條數據,這個數據就會被放在當前會話的一級緩存中
    • 如果會話關閉了,這個會員對應的一級緩存就沒了;但是我們想要的是,會話關閉了,一級緩存中的數據被保存到二級緩存中
    • 新的會話查詢信息,就可以從二級緩存中獲取內容
    • 不同的mapper查詢出的數據會放在自己對應的緩存(map)中

緩存全局有效,一個事務查詢的一個sql得到結果,會被緩存起來,之后只要緩存未被清除,則其他事務如果查詢同一個sql,得到的將會是之前緩存的結果,二級緩存作用范圍大,作用時間長,可能造成的危害也更大,所以在開發中一般很少啟用二級緩存

二級緩存又稱為SqlSessionFactory級緩存,可以在不同的session間緩存

當啟用了二級緩存時,mybatis的查詢順序是,二級緩存-->一級緩存-->數據庫

手動開啟二級緩存:

主配置文件

<!--開啟二級緩存 總開關 -->
    <settings>
        <setting name="cacheEnabled" value="true">
    </setting></settings>

mapper.xml

 <cache>

舉例:

注意:只有查詢才有緩存,根據數據是否需要緩存(修改是否頻繁選擇是否開啟)useCache=“true”

 <select id="getUserById" resulttype="user" usecache="true">
        select * from user where id = #{id}
    </select>

小結:

1.只要開啟了二級緩存,同一個Mapper下就有效

2.所有的數據都會先放在一級緩存中

3.只要當會話提交,或者關閉的時候,才會提交到二級緩存中

4.當啟用了二級緩存時,mybatis的查詢順序是,二級緩存-->一級緩存-->數據庫


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM