Mybatis基礎(chǔ)-復(fù)習(xí)-面試

MyBatis 是一款優(yōu)秀的持久層框架,它支持自定義 SQL、存儲(chǔ)過程以及高級(jí)映射。
MyBatis 免除了幾乎所有的 JDBC 代碼以及設(shè)置參數(shù)和獲取結(jié)果集的工作。
MyBatis 可以通過簡(jiǎn)單的 XML 或注解來配置和映射原始類型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 對(duì)象)為數(shù)據(jù)庫中的記錄。

持久化
持久化就是將程序的數(shù)據(jù)在持久狀態(tài)和瞬時(shí)狀態(tài)轉(zhuǎn)化的過程

內(nèi)存--- 斷電即失

數(shù)據(jù)庫(jdbc) io文件持久化

為什么要持久化?
持久化技術(shù)封裝了數(shù)據(jù)訪問細(xì)節(jié),為大部分業(yè)務(wù)邏輯提供面向?qū)ο蟮腁PI。

  1. 通過持久化技術(shù)可以減少訪問數(shù)據(jù)庫數(shù)據(jù)次數(shù),增加應(yīng)用程序執(zhí)行速度;
  2. 代碼重用性高,能夠完成大部分?jǐn)?shù)據(jù)庫操作;
  3. 松散耦合,使持久化不依賴于底層數(shù)據(jù)庫和上層業(yè)務(wù)邏輯實(shí)現(xiàn),更換數(shù)據(jù)庫時(shí)只需修改配置文件而不用修改代碼。
    持久層
    完成持久化工作的代碼塊
    層界限十分明顯

什么是MyBatis

MyBatis 本是apache的一個(gè)開源項(xiàng)目iBatis, 2010年這個(gè)項(xiàng)目由apache software foundation 遷移到了google code,并且改名為MyBatis 。2013年11月遷移到Github。
MyBatis 是一款優(yōu)秀的持久層框架,它支持自定義 SQL、存儲(chǔ)過程以及高級(jí)映射。
MyBatis 免除了幾乎所有的 JDBC 代碼以及設(shè)置參數(shù)和獲取結(jié)果集的工作。

MyBatis 可以通過簡(jiǎn)單的 XML 或注解來配置和映射原始類型、接口和 Java POJO
搭建環(huán)境
CREATE DATABASE mybatis;
USE mybatis;

CREATE TABLE user (

id int(20) NOt NULL,
name VARCHAR(30)  DEFAULT NULL,
pwd  VARCHAR(30)  DEFAULT NULL,
PRIMARY KEY (id)

)
ENGINE=INNODB
CHARSET=utf8
;
INSERT INTO USER (name,pwd)
VALUES
('lisi','123'),
('wangwu','123'),
('test','123');
導(dǎo)入依賴

<dependencies>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>


<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>


<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
</dependencies>

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

<?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?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="dao/UserMapper.xml"/>
</mappers>
</configuration>
從 XML 中構(gòu)建 SqlSessionFactory
每個(gè)基于 MyBatis 的應(yīng)用都是以一個(gè) SqlSessionFactory 的實(shí)例為核心的。SqlSessionFactory 的實(shí)例可以通過 SqlSessionFactoryBuilder 獲得。而 SqlSessionFactoryBuilder 則可以從 XML 配置文件或一個(gè)預(yù)先配置的 Configuration 實(shí)例來構(gòu)建出 SqlSessionFactory 實(shí)例。
從 XML 文件中構(gòu)建 SqlSessionFactory 的實(shí)例非常簡(jiǎn)單,建議使用類路徑下的資源文件進(jìn)行配置。 但也可以使用任意的輸入流(InputStream)實(shí)例,比如用文件路徑字符串或 file:// URL 構(gòu)造的輸入流。MyBatis 包含一個(gè)名叫 Resources 的工具類,它包含一些實(shí)用方法,使得從類路徑或其它位置加載資源文件更加容易。

public class MybatisUtils {

InputStream inputStream;
SqlSessionFactory sqlSessionFactory;
{
try {
String resource = "/mybatis-config.xml";
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//既然有了 SqlSessionFactory,顧名思義,我們可以從中獲得 SqlSession 的實(shí)例。
// SqlSession 提供了在數(shù)據(jù)庫執(zhí)行 SQL 命令所需的所有方法。
// 你可以通過 SqlSession 實(shí)例來直接執(zhí)行已映射的 SQL 語句s
public SqlSessionFactory getSqlSessionFactory() {
return sqlSessionFactory;
}
從 SqlSessionFactory 中獲取 SqlSession
既然有了 SqlSessionFactory,顧名思義,我們可以從中獲得 SqlSession 的實(shí)例。SqlSession 提供了在數(shù)據(jù)庫執(zhí)行 SQL 命令所需的所有方法。你可以通過 SqlSession 實(shí)例來直接執(zhí)行已映射的 SQL 語句
public interface UserMapper {

public List<User>  getUserList();

}

<?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="dao.UserMapper">
<select id="getUserList" resultType="pojo.User">
select * from User
</select>
</mapper>
public class UserTest {

@Test
public void test(){

    //獲取sqlsession對(duì)象
    SqlSession sqlSession= MybatisUtils.getSqlSession();

    //方式一 getmapper

    UserMapper user = sqlSession.getMapper(UserMapper.class);
    List<User> userList = user.getUserList();
    for (User user1:userList){
        System.out.println(user1);
    }
sqlSession.close();
}

}

作用域(Scope)和生命周期

理解我們之前討論過的不同作用域和生命周期類別是至關(guān)重要的,因?yàn)殄e(cuò)誤的使用會(huì)導(dǎo)致非常嚴(yán)重的并發(fā)問題。


提示 對(duì)象生命周期和依賴注入框架

依賴注入框架可以創(chuàng)建線程安全的、基于事務(wù)的 SqlSession 和映射器,并將它們直接注入到你的 bean 中,因此可以直接忽略它們的生命周期。 如果對(duì)如何通過依賴注入框架使用 MyBatis 感興趣,可以研究一下 MyBatis-Spring 或 MyBatis-Guice 兩個(gè)子項(xiàng)目。


SqlSessionFactoryBuilder

這個(gè)類可以被實(shí)例化、使用和丟棄,一旦創(chuàng)建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 實(shí)例的最佳作用域是方法作用域(也就是局部方法變量)。 你可以重用 SqlSessionFactoryBuilder 來創(chuàng)建多個(gè) SqlSessionFactory 實(shí)例,但最好還是不要一直保留著它,以保證所有的 XML 解析資源可以被釋放給更重要的事情。

SqlSessionFactory

SqlSessionFactory 一旦被創(chuàng)建就應(yīng)該在應(yīng)用的運(yùn)行期間一直存在,沒有任何理由丟棄它或重新創(chuàng)建另一個(gè)實(shí)例。 使用 SqlSessionFactory 的最佳實(shí)踐是在應(yīng)用運(yùn)行期間不要重復(fù)創(chuàng)建多次,多次重建 SqlSessionFactory 被視為一種代碼“壞習(xí)慣”。因此 SqlSessionFactory 的最佳作用域是應(yīng)用作用域。 有很多方法可以做到,最簡(jiǎn)單的就是使用單例模式或者靜態(tài)單例模式。

SqlSession

每個(gè)線程都應(yīng)該有它自己的 SqlSession 實(shí)例。SqlSession 的實(shí)例不是線程安全的,因此是不能被共享的,所以它的最佳的作用域是請(qǐng)求或方法作用域。 絕對(duì)不能將 SqlSession 實(shí)例的引用放在一個(gè)類的靜態(tài)域,甚至一個(gè)類的實(shí)例變量也不行。 也絕不能將 SqlSession 實(shí)例的引用放在任何類型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你現(xiàn)在正在使用一種 Web 框架,考慮將 SqlSession 放在一個(gè)和 HTTP 請(qǐng)求相似的作用域中。 換句話說,每次收到 HTTP 請(qǐng)求,就可以打開一個(gè) SqlSession,返回一個(gè)響應(yīng)后,就關(guān)閉它。 這個(gè)關(guān)閉操作很重要,為了確保每次都能執(zhí)行關(guān)閉操作,你應(yīng)該把這個(gè)關(guān)閉操作放到 finally 塊中。 下面的示例就是一個(gè)確保 SqlSession 關(guān)閉的標(biāo)準(zhǔn)模式:

<pre>try (SqlSession session = sqlSessionFactory.openSession()) {</pre>

<pre> // 你的應(yīng)用邏輯代碼</pre>

<pre>}</pre>

在所有代碼中都遵循這種使用模式,可以保證所有數(shù)據(jù)庫資源都能被正確地關(guān)閉。
CRUD

  1. Namespace
    namespace中的包名要和 Dao、Mapper 接口的包名一致

2.Id:對(duì)應(yīng)的namespace中的方法名
3.parameterType :Sql語句執(zhí)行的參數(shù)
4.resultType :Sql語句執(zhí)行的返回值
public interface UserMapper {
//查詢所有用戶
public List<User> getUserList();
//根據(jù)id查詢用戶
User getUserById(int id);
//insert 一個(gè)用戶
void insertUser(User user);
//修改一個(gè)用戶
void updateUser(User user);
//刪除一個(gè)用戶
void deleted(Integer id);
}


<mapper namespace="dao.UserMapper">
查詢語句
<select id="getUserList" resultType="pojo.User">
select * from User
</select>

<select id="getUserById"  parameterType="int"  resultType="pojo.User">
    select * from User  where id = #{id}
</select>
      添加語句
<insert id="insertUser" parameterType="pojo.User"  >
    insert  into User  (name,pwd) values (#{name} , #{pwd})
</insert>
       修改語句
<update id="updateUser" parameterType="pojo.User" >
    update User set  name = #{name} , pwd = #{pwd}  where  id = #{id}
</update>
       刪除語句
<delete id="deleted" parameterType="Integer">
    delete from  User    where  id = #{id}
</delete>

</mapper>

注意點(diǎn) ; 增刪改需要提交事務(wù)分析錯(cuò)誤

  1. 標(biāo)簽不要匹配錯(cuò)
  2. Resource綁定mapper,需要使用路徑
  3. 程序配置文件必須符合規(guī)范
  4. NullpointerException 沒有注冊(cè)到資源
  5. 輸出的xml文件中存在中文亂碼問題
  6. Maven資源沒有導(dǎo)出問題

萬能Map

圖片.png

圖片.png

圖片.png

Map 傳遞參數(shù),直接在sql中取出key即可 resultType=“map”
對(duì)象傳遞參數(shù),直接在sql中取對(duì)象的屬性即可 resultType=“Object”
只有一個(gè)基本類型參數(shù)的情況下,可以直接在sql中取到
多個(gè)參數(shù)用Map,或者注解

配置解析

MyBatis 的配置文件包含了會(huì)深深影響 MyBatis 行為的設(shè)置和屬性信息。 配置文檔的頂層結(jié)構(gòu)如下:

環(huán)境配置(environments)

MyBatis 可以配置成適應(yīng)多種環(huán)境,這種機(jī)制有助于將 SQL 映射應(yīng)用于多種數(shù)據(jù)庫之中, 現(xiàn)實(shí)情況下有多種理由需要這么做。例如,開發(fā)、測(cè)試和生產(chǎn)環(huán)境需要有不同的配置;或者想在具有相同 Schema 的多個(gè)生產(chǎn)數(shù)據(jù)庫中使用相同的 SQL 映射。還有許多類似的使用場(chǎng)景。

不過要記?。罕M管可以配置多個(gè)環(huán)境,但每個(gè) SqlSessionFactory 實(shí)例只能選擇一種環(huán)境。

Mybatis默認(rèn)事務(wù)管理器是jdbc,連接池: pooled

屬性(properties)

這些屬性可以在外部進(jìn)行配置,并可以進(jìn)行動(dòng)態(tài)替換。你既可以在典型的 Java 屬性文件中配置這些屬性,也可以在 properties 元素的子元素中設(shè)置。jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/e3mall-32?characterEncoding=utf-8
jdbc.username=root
jdbc.password=123456

圖片.png

圖片.png

<properties resource="db.properties"/>
圖片.png

可以直接引入外部文件
可以在其中增加一些屬性配置
如果兩個(gè)文件有同一個(gè)字段,優(yōu)先使用外部配置文件
類型別名(typeAliases)
類型別名可為 Java 類型設(shè)置一個(gè)縮寫名字。 它僅用于 XML 配置,意在降低冗余的全限定類名書寫。

<typeAliases>
<typeAlias type="pojo.User" alias="User" />
</typeAliases>

resultType="User">
也可以指定一個(gè)包名,MyBatis 會(huì)在包名下面搜索需要的 Java Bean
<typeAliases>
<package name="pojo"/>
</typeAliases>

每一個(gè)在包 domain.blog 中的 Java Bean,在沒有注解的情況下,會(huì)使用 Bean 的首字母小寫的非限定類名來作為它的別名
resultType="user"若有注解,則別名為其注解值。見下面的例子:
@Alias("author")
public class Author {
...
}
設(shè)置(settings)這是 MyBatis 中極為重要的調(diào)整設(shè)置,它們會(huì)改變 MyBatis 的運(yùn)行時(shí)行為。 下表描述了設(shè)置中各項(xiàng)設(shè)置的含義、默認(rèn)值等。


圖片.png

圖片.png
圖片.png

映射器(mappers)
既然 MyBatis 的行為已經(jīng)由上述元素配置完了,我們現(xiàn)在就要來定義 SQL 映射語句了。
但首先,我們需要告訴 MyBatis 到哪里去找到這些語句。
在自動(dòng)查找資源方面,Java 并沒有提供一個(gè)很好的解決方案,所以最好的辦法是直接告訴 MyBatis 到哪里去找映射文件。
你可以使用相對(duì)于類路徑的資源引用,或完全限定資源定位符(包括 file:/// 形式的 URL),或類名和包名等

MapperRegistry :注冊(cè)綁定我們的Mapper文件


圖片.png

圖片.png

圖片.png

注意點(diǎn) –方式二和方式三
接口和他的Mapper配置文件必須同名
接口和他的Mapper配置文件在同一包下

生命周期和作用域
圖片.png

理解我們之前討論過的不同作用域和生命周期類別是至關(guān)重要的,因?yàn)殄e(cuò)誤的使用會(huì)導(dǎo)致非常嚴(yán)重的并發(fā)問題。
SqlSessionFactoryBuilder
一旦創(chuàng)建了 SqlSessionFactory,就不再需要它了。

方法作用域(也就是局部方法變量)
SqlSessionFactory(相當(dāng)于數(shù)據(jù)庫連接池)
一旦被創(chuàng)建就應(yīng)該在應(yīng)用的運(yùn)行期間一直存在,沒有任何理由丟棄它或重新創(chuàng)建另一個(gè)實(shí)例。
最簡(jiǎn)單的就是使用單例模式或者靜態(tài)單例模式。
應(yīng)用作用域
SqlSession(連接到連接池的一個(gè)請(qǐng)求)
SqlSession 的實(shí)例不是線程安全的,因此是不能被共享的
請(qǐng)求或方法作用域。
用完關(guān)閉,否則資源被占用


圖片.png

這里面的每個(gè)mapper,就代表一個(gè)具體的業(yè)務(wù)
ResultMap結(jié)果集映射
解決屬性名與數(shù)據(jù)庫字段名不一致的問題
public class User {
private Integer id;
private String username;
private String password;


圖片.png

解決辦法
1.起別名
select id,name ,pwd from User where id = #{id}
改為 select id,name as username,pwd as password from User where id = #{id}

  1. 用resultMap

數(shù)據(jù)庫字段 : id name pwd
實(shí)體類參數(shù): id username ppassword

Column 列 (數(shù)據(jù)庫中的字段) property 屬性 (實(shí)體類中的屬性)

<resultMap id="UserMap" type="user">
<result column="id" property="id"/>
<result column="name" property="username"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserById" parameterType="int" resultMap="UserMap">
select id, name ,pwd from User where id = #{id}
</select>

resultMap 元素是 MyBatis 中最重要最強(qiáng)大的元素。
它可以讓你從 90% 的 JDBC ResultSets 數(shù)據(jù)提取代碼中解放出來,并在一些情形下允許你進(jìn)行一些 JDBC 不支持的操作。
實(shí)際上,在為一些比如連接的復(fù)雜語句編寫映射代碼的時(shí)候,一份 resultMap 能夠代替實(shí)現(xiàn)同等功能的數(shù)千行代碼。
ResultMap 的設(shè)計(jì)思想是,對(duì)簡(jiǎn)單的語句做到零配置,對(duì)于復(fù)雜一點(diǎn)的語句,只需要描述語句之間的關(guān)系就行了。

上述語句只是簡(jiǎn)單地將所有的列映射到 HashMap 的鍵上,這由 resultType 屬性指定。
雖然在大部分情況下都?jí)蛴?,但?HashMap 并不是一個(gè)很好的領(lǐng)域模型。
你的程序更可能會(huì)使用 JavaBean 或 POJO(Plain Old Java Objects,普通老式 Java 對(duì)象)作為領(lǐng)域模型。MyBatis 對(duì)兩者都提供了支持。

沒有一個(gè)需要顯式配置 ResultMap,這就是 ResultMap 的優(yōu)秀之處——你完全可以不用顯式地配置它們。 雖然上面的例子不用顯式配置 ResultMap。


如何數(shù)據(jù)庫字段和實(shí)體類屬性一致 可以省略,因?yàn)閙ybatis會(huì)自動(dòng)生成

            日志
    日志工廠
圖片.png

SLF4J
LOG4J 【掌握】
LOG4J2
JDK_LOGGING
COMMONS_LOGGING
STDOUT_LOGGING 【掌握】
NO_LOGGING

在mybatis-config.xml配置文件中配置

<settings>

<setting name="logImpl" value=" STDOUT_LOGGING"/>

</settings>

STDOUT_LOGGING :標(biāo)準(zhǔn)日志輸出

圖片.png

Log4j

Log4j是Apache的一個(gè)開源項(xiàng)目,通過使用Log4j,我們可以控制日志信息輸送的目的地是控制臺(tái)、文件、GUI組件,甚至是套接口服務(wù)器、NT的事件記錄器、UNIX Syslog守護(hù)進(jìn)程等;我們也可以控制每一條日志的輸出格式;通過定義每一條日志信息的級(jí)別,我們能夠更加細(xì)致地控制日志的生成過程。最令人感興趣的就是,這些可以通過一個(gè)配置文件來靈活地進(jìn)行配置,而不需要修改應(yīng)用的代碼。

  1. 導(dǎo)包

  2. 寫配置文件

log4j.properties

### 設(shè)置### log4j.rootLogger = debug,stdout,D,E ### 輸出信息到控制抬 ### log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n ### 輸出DEBUG 級(jí)別以上的日志到=E://logs/error.log ### log4j.appender.D = org.apache.log4j.DailyRollingFileAppender log4j.appender.D.File = E://logs/log.log log4j.appender.D.Append = true log4j.appender.D.Threshold = DEBUG log4j.appender.D.layout = org.apache.log4j.PatternLayout log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n ### 輸出ERROR 級(jí)別以上的日志到=E://logs/error.log ### log4j.appender.E = org.apache.log4j.DailyRollingFileAppender log4j.appender.E.File =E://logs/error.log log4j.appender.E.Append = true log4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayout log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n

<pre>3.在mybatis-config.xml配置文件中配置</pre>

** <settings>

<setting name="logImpl" value="LOG4J"/>

</settings>

簡(jiǎn)單使用

<pre style="background:white">1導(dǎo)入包 org.apache.log4j.Logger;</pre>

2.日志對(duì)象

static Logger logger = Logger.getLogger(mybatilsTest.class); //mybatilsTest

3.日志級(jí)別

public void logtset(){ logger.info("info進(jìn)入"); logger.debug("debug進(jìn)入"); ------調(diào)試的時(shí)候可以用 logger.error("錯(cuò)誤啦");
}

圖片.png

分頁
Sql
Select * from XXX LIMIT startIndex , pageSize;

使用mybatis實(shí)現(xiàn)分頁,核心sql

  1. 接口
    //分頁
    public List<User> getlimitUser(Map<String,Integer> map);

  2. Mapper.xml

    <resultMap id="UserMap" type="user">

    <result column="name" property="username"/>
    <result column="pwd" property="password"/>
    </resultMap>


<select id="getlimitUser" parameterType="map" resultMap="UserMap">
select * from User LIMIT #{startIndex},#{pageSize}
</select>

  1. 測(cè)試
    @Test
    public void limit(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    Map<String, Integer> map=new HashMap<String, Integer>();

    map.put("startIndex",0);
    map.put("pageSize",2);

    List<User> list = mapper.getlimitUser(map);
    for (User user : list) {
    System.out.println(user);
    }

}

            分頁插件
           Pagehelper
圖片.png

1). 使用 Maven

在 pom.xml 中添加如下依賴:

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>最新版本</version>
</dependency>

2. 配置攔截器插件

1. 在 MyBatis 配置 xml 中配置攔截器插件

<plugins>

<plugin interceptor="com.github.pagehelper.PageInterceptor">

<property name="param1" value="value1"/>

</plugin>

</plugins>

2. 在 Spring 配置文件中配置攔截器插件

使用 spring 的屬性配置方式,可以使用 plugins 屬性像下面這樣配置:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

<property name="plugins">

<array>

<bean class="com.github.pagehelper.PageInterceptor">

<property name="properties">

<value>

params=value1

</value>

</property>

</bean>

</array>

</property>

</bean>

https://pagehelper.github.io/docs/howtouse/

使用注解開發(fā)

對(duì)于像 BlogMapper 這樣的映射器類來說,還有另一種方法來完成語句映射。 它們映射的語句可以不用 XML 來配置,而可以使用 Java 注解來配置。比如,上面的 XML 示例可以被替換成如下的配置:

package org.mybatis.example;

public interface BlogMapper {

@Select("SELECT * FROM blog WHERE id = #{id}")

Blog selectBlog(int id);

}

使用注解來映射簡(jiǎn)單語句會(huì)使代碼顯得更加簡(jiǎn)潔,但對(duì)于稍微復(fù)雜一點(diǎn)的語句,Java 注解不僅力不從心,還會(huì)讓你本就復(fù)雜的 SQL 語句更加混亂不堪。 因此,如果你需要做一些很復(fù)雜的操作,最好用 XML 來映射語句。


圖片.png

圖片.png

本質(zhì): 反射機(jī)制實(shí)現(xiàn)
底層: 動(dòng)態(tài)代理

Mybatis工作原理
圖片.png

在工具類可以設(shè)置默認(rèn)提交事務(wù)
圖片.png

圖片.png

@Param

1.關(guān)于@Param
@Param是MyBatis所提供的(org.apache.ibatis.annotations.Param),作為Dao層的注解,作用是用于傳遞參數(shù),從而可以與SQL中的的字段名相對(duì)應(yīng),一般在2=<參數(shù)數(shù)<=5時(shí)使用最佳。


圖片.png
  1. 將傳入的數(shù)據(jù)都當(dāng)成一個(gè)字符串,會(huì)對(duì)自動(dòng)傳入的數(shù)據(jù)加一個(gè)雙引號(hào)。如:order by #user_id#,如果傳入的值是111,那么解析成sql時(shí)的值為order by "111", 如果傳入的值是id,則解析成的sql為order by "id".

  1. 將傳入的數(shù)據(jù)直接顯示生成在sql中。如:order byuser_id$,如果傳入的值是111,那么解析成sql時(shí)的值為order by user_id, 如果傳入的值是id,則解析成的sql為order by id.
  2. 方式能夠很大程度防止sql注入。

4.$方式無法防止Sql注入。

5.方式一般用于傳入數(shù)據(jù)庫對(duì)象,例如傳入表名.    6.一般能用#的就別用.

MyBatis排序時(shí)使用order by 動(dòng)態(tài)參數(shù)時(shí)需要注意,用$而不是#

字符串替換
默認(rèn)情況下,使用#{}格式的

//方法存在多個(gè)參數(shù),所以參數(shù)前面必須加上@Param(“xxx”)注解

<select id="getUserByIdByname" resultMap="UserMap" parameterType="User">
select * from User where id =#{id} and name=#{name}
</select>
//根據(jù)多條件查詢
public User getUserByIdByname(@Param("id")Integer id , @Param("name")String name);
//根據(jù)條件查詢
User wangwu = mapper.getUserByIdByname(2, "wangwu");
System.out.println(wangwu);

                    注解完成CRUD

<mappers>
<mapper class="cn.ma.dao.UserMapper"/>
</mappers>

public interface UserMapper {

//查詢所有用戶
@Select("select * from User")
public List<User> getUserList();

//根據(jù)條件查詢
@Select("select * from User where id =#{id} and name=#{name}")
public User getUserByIdByname(@Param("id")Integer id ,@Param("name")String name);

//insert xxx into
@Insert(" insert  into User  (name,pwd) values (#{name} , #{pwd})")
public void insertUser(User user);

//update setxxx
@Update(" update User set  name = #{name} , pwd = #{pwd}  where  id = #{id} ")
public void updateUserById(User user);

//deleted form xxx
@Delete("delete from  User    where  id = #{id}")
public void deleteById(Integer id);

}

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

/*      //查詢所有用戶
    List<User> userList = mapper.getUserList();

    for (User user : userList) {
        System.out.println(user);
    }*/

   /* //根據(jù)條件查詢
    User wangwu = mapper.getUserByIdByname(2, "wangwu");
    System.out.println(wangwu);*/

   /* //insert xxx into
    User user=new User();
    user.setName("添加");
    user.setPwd("21212");
    mapper.insertUser(user);*/

        /*//update setxxx
     User user=new User(12,"修改","修改密碼");
    mapper.updateUserById(user);
    */

     /*   //deleted form xxx
       mapper.deleteById(7);*/
}

}

                    復(fù)雜查詢         
                    多對(duì)一處理
    多個(gè)學(xué)生對(duì)應(yīng)一個(gè)老師

對(duì)于學(xué)生而言, 關(guān)聯(lián)……多個(gè)學(xué)生,關(guān)聯(lián)一個(gè)老師 【多對(duì)一】

對(duì)于老師而言, 集合……一個(gè)老師可以有多個(gè)學(xué)生。 【一對(duì)多】

        實(shí)體類

public class Student implements Serializable {

private Integer id;
private String name;

//------private  Integer tid;
//學(xué)生需要關(guān)聯(lián)一個(gè)老師   tid
private Teacher teacher;

public class Teacher {

private Integer id;
private String  name;

create table teacher(

id int(10) NOT NULL,
name VARCHAR(20)  NOT null,

primary key(id)

)
ENGINE=INNODB
DEFAULT CHARSET=utf8

INSERT INTO teacher (id,name) VALUES (2,'李老師');

create table student(

id int(10) NOT NULL,
name VARCHAR(20)  NOT null,
tid int(10) NOT NULL,
primary key(id),

KEY fktid (tid),
CONSTRAINT fktid FOREIGN KEY (tid) REFERENCES teacher(id)

)
ENGINE=INNODB
DEFAULT CHARSET=utf8

INSERT INTO student (id,name,tid) VALUES (1,'小明',1);
INSERT INTO student (id,name,tid) VALUES (2,'小紅',2);
INSERT INTO student (id,name,tid) VALUES (3,'小南',1);
INSERT INTO student (id,name,tid) VALUES (4,'小球',2);


圖片.png

圖片.png
圖片.png

圖片.png

· association – 一個(gè)復(fù)雜類型的關(guān)聯(lián);許多結(jié)果將包裝成這種類型

  • 嵌套結(jié)果映射 – 關(guān)聯(lián)可以是 resultMap 元素,或是對(duì)其它結(jié)果映射的引用

· collection – 一個(gè)復(fù)雜類型的集合

  • 嵌套結(jié)果映射 – 集合可以是 resultMap 元素,或是對(duì)其它結(jié)果映射的引用

//查詢所有學(xué)生信息,以及對(duì)應(yīng)的老師信息

SELECT s.id,s.name,t.name from student s

JOIN teacher t

on t.id = s.tid;

SELECT s.id,s.name,t.name from student s ,teacher t

where t.id = s.tid;

**

mybatis的javaType和ofType

都是指定對(duì)象的類型 不同的是當(dāng)使用反向查詢select從另一個(gè)maper文件中取出數(shù)據(jù)時(shí)必須用ofType

都可以為collection和association是指定對(duì)象的類型,

都不是必須寫的, 只有反向select時(shí)需要ofType;

按照查詢嵌套處理

<mapper namespace="cn.ma.dao.StudentMapper">

<resultMap id="StudentMap" type="Student">
<id property="id" column="id"></id>

</resultMap> ** <select id="getStudnetList" resultMap="StudentMap">
select *** from Student
</select>
<select id="getTeacher" resultType="Teacher">
select *** from Teacher where id =#{tid}
</select>
</mapper>

@Test public void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); List<Student> studnetList = mapper.getStudnetList(); for (Student student : studnetList) { System.out.println(student);
}
}

按照結(jié)果嵌套處理

<pre style="background:white">** <resultMap id="StudentMap2" type="Student">

<id property="id" column="id"></id>

<result property="id" column="id"/>

<result property="name" column="name"/>

</association>

</resultMap>

<select id="getStudnetList2" resultMap="StudentMap2">

SELECT s.id,s.name,t.name

from student s ,teacher t where t.id = s.tid;

</select></pre>

@Test public void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); List<Student> studnetList = mapper.getStudnetList2(); for (Student student : studnetList) { System.out.println(student);
}
}

一對(duì)多處理

一個(gè)老師擁有多個(gè)學(xué)生

對(duì)于老師就是一對(duì)多關(guān)系

實(shí)體類

<pre style="background:white"> public class Teacher { private Integer id; private String name; //一個(gè)老師擁有多個(gè)學(xué)生 private List<Student> students;

}</pre>

public class Student implements Serializable { private Integer id; private String name; private Integer tid;

<pre style="background:white">** <select id="getTeacherAndStudentById" resultMap="TeacherMap">

SELECT t.id tid, t.name tname, s.id sid, s.name sname FROM teacher t , student s WHERE t.id=s.tid

AND t.id=#{tid}

</select> ** <select id="getTeacherAndStudentById" resultMap="TeacherMap">

SELECT t.id tid, t.name tname, s.id sid, s.name sname FROM teacher t , student s WHERE t.id=s.tid

AND t.id=#{tid}

</select>

<resultMap id="TeacherMap" type="Teacher">

<result property="id" column="tid"/>

<result property="name" column="tname"/> ** <collection property="students" ofType="Student">

  <result property="id" column="sid"/>

<result property="name" column="sname"/>

<result property="tid" column="tid"/>

</collection>

</resultMap></pre>

@Test public void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class); Teacher teacherById = mapper.getTeacherAndStudentById(1); System.out.println(teacherById); //輸出結(jié)果 Teacher{id=1, name='王老師',
// students=[Student{id=1, name='
小明', tid=1}, Student{id=3, name='小南', tid=1}]} MybatisUtils.close();

}


圖片.png

圖片.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容