Mybatis 3.4.6知識整理

一、前言

最近找了一些Mybatis的視頻來學習,光看不練假把式,以這篇文章來鞏固一下學到的知識,如有不足,請多多指教。

二、環境準備#

Mybatis 官方網站:http://blog.mybatis.org/

Mybatis 版本:mybatis-3.4.6

軟件: IntelliJ IDEA 2018.2

JDK: jdk1.8.0_181

數據庫:MySQL 5.7.20

連接工具:Navicat

源碼地址:https://github.com/cyikns/myBatisStudy.git

三、下載Mybatis

打開官方網站會自動跳轉到MyBatis博客,打開之後會看到如下這樣的頁面。點擊頁面右側的Mybatis for java下GitHub Project。
打開鏈接後,跳轉到GitHub,在此附上鍊接 https://github.com/mybatis,選擇Mybatis-3。
進入頁面後,拖動到頁面最底端,選擇 DownLoad Latest。
進入Mybatis下載頁面,當前最新版本是3.4.6,在這裏我就用最新版的來做測試。將mybatis-3.4.6.zip文件下載到電腦相應位置,Source code 是源碼,ZIP對應windows系統,tar.gz對應linux系統,按需下載,至此mybatis下載完畢。

四、myBatis入門

1、準備數據

具體操作參考我上一篇微博。
https://blog.csdn.net/m0_38131049/article/details/81457856

數據如下圖:
tb_user

tb_order

2、環境搭建

本例採用Maven來進行架構,使用Maven 3.5.4版本,在pom文件中添加依賴

<?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>cn.xyikns</groupId>
    <artifactId>myBatis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>

        <!--導入mybatis包-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>

        <!--mysql數據庫驅動-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>

    </dependencies>

    <!--指定程序JDK版本和編譯版本-->

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>

    </build>
</project>

加入配置文件
log4j.properties

### 設置###
log4j.rootLogger = debug,stdout

### 輸出信息到控制擡 ###
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 級別以上的日誌到=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 級別以上的日誌到=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

sqlMapConfig.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>
    <properties resource="db.properties"/>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
<mappers>
    <mapper resource="sqlmap/User.xml"/>
</mappers>
</configuration>

創建POJO
USER

package cn.cyikns.pojo;

import java.io.Serializable;

/**
 * @author cyikns
 * @create 2018-08-07 18:49
 */
public class User implements Serializable {

    private int id;
    private String username;
    private String password;
    private String address;

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

Order

package cn.cyikns.pojo;

import java.io.Serializable;

/**
 * @author cyikns
 * @create 2018-08-07 19:53
 */
public class Order implements Serializable {
    private int id;
    private int userId;
    private String shoppingName;
    private int status;


    public int getId() {
        return id;
    }

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

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public String getShoppingName() {
        return shoppingName;
    }

    public void setShoppingName(String shoppingName) {
        this.shoppingName = shoppingName;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }
}

在config下的sqlmap目錄下創建sql映射文件User.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">
<!-- namespace:命名空間,用於隔離sql,還有一個很重要的作用,後面會講 -->
<mapper namespace="test">
</mapper>

得到如圖所示的mybatis工程

3、回顧JDBC連接數據庫的方法

package cn.cyikns.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 回顧JDBC連接數據庫
 *
 * @author cyikns
 * @create 2018-08-07 16:07
 */
public class JDBCReview {

    public static void main(String[] args) throws SQLException {
        Connection conn = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;


        try {
            //加載數據庫驅動
            Class.forName("com.mysql.jdbc.Driver");

            //通過驅動管理類獲取數據庫連接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "sql_user", "Sql_passord");
            //定義SQL語句   ?表示佔位符
            String str = "select * from tb_user where id = ?";
            //獲取預處理statement
            statement = conn.prepareStatement(str);
        // 設置參數,第一個參數爲sql語句中參數的序號(從1開始),第二個參數爲設置的參數值
            statement.setInt(1, 3);

            resultSet = statement.executeQuery();

            while (resultSet.next()) {

                System.out.println(resultSet.getString("username"));
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (resultSet != null) {
                resultSet.close();
            }

            if (statement != null) {
                statement.close();
            }

            if (conn != null) conn.close();
        }

    }
}

這是最原始的jdbc方法(未經封裝)實現的查詢數據庫表的操作。
得出的結果如下

會有一段WARN

Establishing SSL connection without server’s identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn’t set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to ‘false’. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
大體的意思就是:建議不要在沒有服務器身份驗證的情況下建立SSL連接。 根據MySQL 5.5.45 +,5.6.26 +和5.7.6+要求如果未設置顯式選項,則必須默認建立SSL連接。 爲了符合不使用SSL的現有應用程序,verifyServerCertificate屬性設置爲“false”。 您需要通過設置useSSL = false顯式禁用SSL,或者設置useSSL = true併爲服務器證書驗證提供信任庫。

4、myBatis入門開發

JAVA類

package cn.cyikns.test;

import cn.cyikns.pojo.User;
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 org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;


/**
 * 測試類
 *
 * @author cyikns
 * @create 2018-08-07 20:23
 */
public class SimpleTest {

    //根據用戶id查詢用戶
    @Test
    public void queryUserById() {
        //獲取資源文件
        String resource = "sqlMapConfig.xml";
        try {
            //獲得輸入流
            InputStream inputStream = Resources.getResourceAsStream(resource);
            //獲取sessionFactory
            SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //打開sqlSession
            SqlSession sqlSession = sessionFactory.openSession();
            //查詢
            User user = sqlSession.selectOne("queryUserById", 1);
            //輸出結果
            System.out.println(user);

            sqlSession.commit();

            sqlSession.close();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

    //模糊查詢
    @Test
    public void queryUser() {
        //獲取資源文件
        String resource = "sqlMapConfig.xml";
        try {
            //獲得輸入流
            InputStream inputStream = Resources.getResourceAsStream(resource);
            //獲取sessionFactory
            SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //打開sqlSession
            SqlSession sqlSession = sessionFactory.openSession();
            //查詢
            List<User> users = sqlSession.selectList("queryUser", "張");

            for (User user : users) {

                //輸出結果
                System.out.println(user);
            }

            sqlSession.commit();

            sqlSession.close();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

    //根據ID修改數據
    @Test
    public void updateUser() {
        //獲取資源文件
        String resource = "sqlMapConfig.xml";
        try {
            //獲得輸入流
            InputStream inputStream = Resources.getResourceAsStream(resource);
            //獲取sessionFactory
            SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //打開sqlSession
            SqlSession sqlSession = sessionFactory.openSession();
            //查詢
            User user = new User();
            user.setId(3);
            user.setUsername("東方不敗");
            user.setPassword("aabb");
            user.setAddress("湖北省武漢市黃梅縣一天門村");

            int count = sqlSession.update("updateUserById", user);
            System.out.println(count + "--->" + user);
            sqlSession.commit();

            sqlSession.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //根據ID刪除數據
    @Test
    public void delUser() {
        //獲取資源文件
        String resource = "sqlMapConfig.xml";
        try {
            //獲得輸入流
            InputStream inputStream = Resources.getResourceAsStream(resource);
            //獲取sessionFactory
            SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //打開sqlSession
            SqlSession sqlSession = sessionFactory.openSession();

            sqlSession.delete("delUserById", 12);
            sqlSession.commit();

            sqlSession.close();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }


    //    增加一條數據
    @Test
    public void addOneUser() {
        try {
            InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
            SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession sqlSession = sessionFactory.openSession();

            User user = new User();
            user.setUsername("東xi不敗");
            user.setPassword("aabb");
            user.setAddress("湖北省武漢市黃梅縣一天門村");

            int insert = sqlSession.insert("addUser", user);
            System.out.println(user);
            sqlSession.commit();//mybatis不會自動提交事務,所以需要手動提交
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

User.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">
<!-- namespace:命名空間,用於隔離sql,還有一個很重要的作用,後面會講 -->
<mapper namespace="test">

    <select id="queryUserById" parameterType="int" resultType="cn.cyikns.pojo.User">
      select * from tb_user where id = #{id}
    </select>

    <select id="queryUser" parameterType="String" resultType="cn.cyikns.pojo.User">
      select * from tb_user where username like "%"#{values}"%"
    </select>

    <update id="updateUserById" parameterType="cn.cyikns.pojo.User">
        update tb_user set username = #{username},password = #{password},address = #{address} where id = #{id}
    </update>

    <delete id="delUserById" parameterType="int" timeout="5000">
        delete from tb_user where id = #{id}
    </delete>

    <insert id="addUser" parameterType="cn.cyikns.pojo.User" timeout="5000">
    <!-- selectKey 標籤實現主鍵返回 -->
    <!-- keyColumn:主鍵對應的表中的哪一列 -->
    <!-- keyProperty:主鍵對應的pojo中的哪一個屬性 -->
    <!-- order:設置在執行insert語句前執行查詢id的sql,還是在執行insert語句之後執行查詢id的sql ,一般而言返回類型是Integer選擇AFTER,uuid選擇BEFORE-->
    <!-- resultType:設置返回的id的類型 -->

        <selectKey keyColumn="id" keyProperty="id" order="AFTER" resultType="int">
            select LAST_INSERT_ID()
        </selectKey>
        insert into tb_user(username, password, address) values (#{username},#{password},#{address})
    </insert>
</mapper>

小結:

1.其中#{}表示一個佔位符號,通過#{}可以實現preparedStatement向佔位符中設置值,自動進行java類型和jdbc類型轉換。#{}可以有效防止sql注入。 #{}可以接收簡單類型值或pojo屬性值。 如果parameterType傳輸單個簡單類型值,#{}括號中可以是value或其它名稱。
sql {}可以將parameterType 傳入的內容拼接在sql中且不進行jdbc類型轉換, pojoparameterType {}括號中只能是value。
2.parameterType:指定輸入參數類型,mybatis通過ognl從輸入對象中獲取參數值拼接在sql中。
resultType:指定輸出結果類型,mybatis將sql查詢結果的一行記錄數據映射爲resultType指定類型的對象。如果有多條數據,則分別進行映射,並把對象放到容器List中
3.selectOne查詢一條記錄,如果使用selectOne查詢多條記錄則拋出異常:
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70)

selectList可以查詢一條或多條記錄。

5、myBatis 動態代理開發(推薦)

5.1 開發規範

Mapper接口開發方法只需要程序員編寫Mapper接口(相當於Dao接口),由Mybatis框架根據接口定義創建接口的動態代理對象,代理對象的方法體同上。

Mapper接口開發需要遵循以下規範:
1、 Mapper.xml文件中的namespace與mapper接口的類路徑相同。
2、 Mapper接口方法名和Mapper.xml中定義的每個statement的id相同
3、 Mapper接口方法的輸入參數類型和mapper.xml中定義的每個sql 的parameterType的類型相同
4、 Mapper接口方法的輸出參數類型和mapper.xml中定義的每個sql的resultType的類型相同

5.2 映射文件

<?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">
<!-- namespace:命名空間,用於隔離sql,還有一個很重要的作用,即服務於動態代理開發,填上包名 -->
<mapper namespace="cn.cyikns.mapper.UserMapper">

    <select id="queryUserById" parameterType="int" resultType="cn.cyikns.pojo.User">
      select * from tb_user where id = #{id}
    </select>

    <select id="queryUser" parameterType="String" resultType="cn.cyikns.pojo.User">
      select * from tb_user where username like "%"#{values}"%"
    </select>

    <update id="updateUserById" parameterType="cn.cyikns.pojo.User">
        update tb_user set username = #{username},password = #{password},address = #{address} where id = #{id}
    </update>

    <delete id="delUserById" parameterType="int" timeout="5000">
        delete from tb_user where id = #{id}
    </delete>

    <insert id="addUser" parameterType="User" timeout="5000">
        <selectKey keyColumn="id" keyProperty="id" order="AFTER" resultType="int">
            select LAST_INSERT_ID()
        </selectKey>
        insert into tb_user(username, password, address) values (#{username},#{password},#{address})
    </insert>
</mapper>

5.3 接口文件

package cn.cyikns.mapper;

import cn.cyikns.pojo.User;

/**
 * @author cyikns
 * @create 2018-08-08 10:12
 */
public interface UserMapper {

    void addUser(User user);

    User selectUserById(int id);
}

5.4 注意事項


注意:由於將xml文件放在maven工程中,需要在pom.xml文件中添加資源文件

<build>
  <!--指定資源文件-->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
</build>

否則會報一個找不到方法的錯誤

5.5 別名

5.5.1 mybatis支持別名

別名       映射的類型
_byte       byte
_long       long
_short       short
_int       int
_integer       int
_double       double
_float       float
_boolean       boolean
string       String
byte       Byte
long       Long
short       Short
int       Integer
integer       Integer
double       Double
float       Float
boolean       Boolean
date       Date
decimal       BigDecimal
bigdecimal       BigDecimal
map       Map

5.5.2 自定義別名

<typeAliases>
    <!--單個別名定義-->
    <typeAlias type="User" alias="cn.cyikns.pojo.User"/>
    <!-- 批量別名定義,掃描整個包下的類,別名爲類名(大小寫不敏感) -->
    <package name="cn.cyikns.pojo"/>
</typeAliases>

6、原理了解

6.1 parameterType(輸入類型)

1) 傳遞簡單類型
使用#{任意字符}佔位符,或者{value}進行sql拼接。 2)  傳遞POJO對象 Mybatis使用ognl表達式解析對象字段的值,#{}或者 {}括號中的值爲pojo屬性名稱。
3 傳遞pojo包裝對象
編寫QueryVo

package cn.cyikns.pojo;

import java.io.Serializable;

/**
 * @author cyikns
 * @create 2018-08-08 14:11
 */
public class QueryVo implements Serializable {

    //包含其他的POJO
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

UserMapper.xml

UserMapper.java

測試代碼

 //測試輸入對象是QueryVo
    @Test
    public void testQueryUserByQueryVo() {
        try {
            InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);

            QueryVo vo = new QueryVo();

            User user1 = new User();
            user1.setUsername("張");

            vo.setUser(user1);

            List<User> users = mapper.queryUserByQueryVo(vo);

            for (User user : users) {

                System.out.println(user);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

結果

6.2 resultType(輸出類型)

1)輸出簡單類型
輸出簡單類型必須查詢出來的結果集有一條記錄,最終將第一個字段的值轉換爲輸出類型。
2)輸出POJO對象
前面有
3)輸出POJO列表
前面有

6.3 resultMap

resultType可以指定將查詢結果映射爲pojo,但需要pojo的屬性名和sql查詢的列名一致方可映射成功。
如果sql查詢字段名和pojo的屬性名不一致,可以通過resultMap將字段名和屬性名作一個對應關係 ,resultMap實質上還需要將查詢結果映射到pojo對象中。
resultMap可以實現將查詢結果映射爲複雜類型的pojo,比如在查詢結果映射對象中包括pojo和list實現一對一查詢和一對多查詢。
例如:查詢訂單表order的所有數據

一般情況而言

返回的值userId和ShoppingName都是不正確的

此時需要使用resultMap屬性,如下所示:

得到的結果就是正確的

注意:1對1時,POJO中名稱與列名稱一致可以忽略不寫,其他情況則不能省略

6.4 動態SQL

UserMapper.java

package cn.cyikns.mapper;

import cn.cyikns.pojo.QueryVo;
import cn.cyikns.pojo.User;

import java.util.List;

/**
 * @author cyikns
 * @create 2018-08-08 10:12
 */
public interface UserMapper {

    void addUser(User user);

    User selectUserById(int id);

    List<User> queryUserByQueryVo(QueryVo vo);

    List<User> queryUser(User user);
}

測試方法

@Test
    public void testQueryUserByUser() {
        try {
            InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);


            User user1 = new User();
            user1.setUsername("張");

            user1.setPassword("1234");

            List<User> users = mapper.queryUser(user1);

            for (User user : users) {

                System.out.println(user);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

數據庫數據

6.4.1 if 標籤

 <!--改造前-->
    <select id="queryUser" parameterType="user" resultType="user">
    SELECT id, username,password,address FROM tb_user
    WHERE password = #{password} AND username LIKE
    '%${username}%'
  </select>
    <!--改造後-->
    <select id="queryUser" parameterType="user" resultMap="user">
        select id,username,password,address from tb_user
        where 1=1
    <!--注意字符串類型的數據需要做不等於空字符串校驗。-->
        <if test="password != null and password != ''">
            and password = #{password}
        </if>
        <if test="username != null and username != ''">
            and username LIKE
            '%${username}%'
        </if>

    </select>

6.4.2 Where標籤

<!--改造後2-->
    <select id="queryUserList" parameterType="user" resultMap="user">
        select * from tb_user
        <!-- where標籤可以自動添加where,同時處理sql語句中第一個and關鍵字(前and) -->
        <where>
            <if test="password != null and password != ''">
                and password = #{password}
            </if>
            <if test="username != null and username != ''">
                and username LIKE "%"#{username}"%"
            </if>
        </where>
    </select>

6.4.3 Sql片段

<!-- 聲明sql片段 -->
    <sql id="refid">
        SELECT * FROM
    </sql>


<!--改造後3-->
    <select id="queryUserList" parameterType="user" resultMap="user">
        <include refid="refid"/>
        tb_user
        <!-- where標籤可以自動添加where,同時處理sql語句中第一個and關鍵字(前and) -->
        <where>
            <if test="password != null and password != ''">
                and password = #{password}
            </if>
            <if test="username != null and username != ''">
                and username LIKE "%"#{username}"%"
            </if>
        </where>
    </select>

6.4.4 foreach標籤

向sql傳遞數組或List,mybatis使用foreach解析

SELECT * FROM tb_user WHERE id IN (1,13,26)

在QueryVo中

<!--foreach標籤
        SELECT * FROM tb_user WHERE id IN (1,13,26)<br>
    -->
    <select id="queryUserForeach" parameterType="QueryVo" resultType="user">
        <include refid="refid"/>
        tb_user
        where id in
        <!-- foreach標籤,進行遍歷 -->
        <!-- collection:遍歷的集合,這裏是QueryVo的ids屬性 -->
        <!-- item:遍歷的項目,可以隨便寫,,但是和後面的#{}裏面要一致 -->
        <!-- open:在前面添加的sql片段 -->
        <!-- close:在結尾處添加的sql片段 -->
        <!-- separator:指定遍歷的元素之間使用的分隔符 -->

        <foreach collection="ids" item="id" open="(" close=")" separator=",">
            #{id}
        </foreach>
    </select>

如果直接使用List類型,那麼parameterType=”list”

<!--foreach標籤
        SELECT * FROM tb_user WHERE id IN (1,13,26)<br>
    -->
    <select id="queryUserForeach" parameterType="list" resultType="user">
        <include refid="refid"/>
        tb_user
        where id in
        <!-- foreach標籤,進行遍歷 -->
        <!-- collection:遍歷的集合,List必須寫list -->
        <!-- item:遍歷的項目,可以隨便寫,,但是和後面的#{}裏面要一致 -->
        <!-- open:在前面添加的sql片段 -->
        <!-- close:在結尾處添加的sql片段 -->
        <!-- separator:指定遍歷的元素之間使用的分隔符 -->

        <foreach collection="list" item="id" open="(" close=")" separator=",">
            #{id}
        </foreach>
    </select>

如果使用數組類型,那麼parameterType =“java.util.Arrays”

 <!--foreach標籤
        SELECT * FROM tb_user WHERE id IN (1,13,26)<br>
    -->
    <select id="queryUserForeach" parameterType="java.util.Arrays" resultType="user">
        <include refid="refid"/>
        tb_user
        where id in
        <!-- foreach標籤,進行遍歷 -->
        <!-- collection:遍歷的集合,數組必須寫array -->
        <!-- item:遍歷的項目,可以隨便寫,,但是和後面的#{}裏面要一致 -->
        <!-- open:在前面添加的sql片段 -->
        <!-- close:在結尾處添加的sql片段 -->
        <!-- separator:指定遍歷的元素之間使用的分隔符 -->

        <foreach collection="array" item="id" open="(" close=")" separator=",">
            #{id}
        </foreach>
    </select>

6.5 關聯查詢

6.5.1 一對一

方法一:使用ResultType
使用resultType,改造訂單pojo類,此pojo類中包括了訂單信息和用戶信息
這樣返回對象的時候,mybatis自動把用戶信息也注入進來了

1)改造POJO

package cn.cyikns.pojo;

/**
 * @author cyikns
 * @create 2018-08-08 17:25
 */
public class OrderUser extends Order {

    private String username;
    private String address;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

2)編寫接口

List<OrderUser> queryAllOrders();

3)編寫OrderMapper.xml

<select id="queryAllOrders" resultType="orderUser" timeout="5000">
        select
            o.id,
            o.user_id,
            u.username,
            o.shopping_name,
            u.address
        from
            tb_order o
        left join
            tb_user u
        on
            o.user_id = u.id
    </select>

4)寫測試代碼

 @Test
    public void testQueryAllOrders() {
        try {
            InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession sqlSession = sqlSessionFactory.openSession();

            OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);

            List<OrderUser> orders = mapper.queryAllOrders();

            for (OrderUser order : orders) {
                System.out.println(order);
            }


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

5)結果

方法二:使用ResultMap
在Order類中加入User屬性,user屬性中用於存儲關聯查詢的用戶信息,因爲訂單關聯查詢用戶是一對一關係,所以這裏使用單個User對象存儲關聯查詢的用戶信息。

1) pojo類

package cn.cyikns.pojo;

import java.io.Serializable;

/**
 * @author cyikns
 * @create 2018-08-07 19:53
 */
public class Order implements Serializable {
    private int id;
    private int userId;
    private String shoppingName;
    private int status;

    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public int getId() {
        return id;
    }

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

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public String getShoppingName() {
        return shoppingName;
    }

    public void setShoppingName(String shoppingName) {
        this.shoppingName = shoppingName;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }


    @Override
    public String toString() {
        return "Order{" +
                "id=" + id +
                ", userId=" + userId +
                ", shoppingName='" + shoppingName + '\'' +
                ", status=" + status +
                ", user=" + user +
                '}';
    }
}

2)寫接口

List<Order> queryOrderUseResultMap1();

3)編寫OrderMapper.xml

<resultMap id="orderUserResultMap" type="Order">
    <id property="id" column="id"/>
    <result column="user_id" property="userId"/>
    <result column="shopping_name" property="shoppingName"/>

    <!-- association :配置一對一屬性 -->
    <!-- property:order裏面的User屬性名 -->
    <!-- javaType:屬性類型 -->
    <association property="user" javaType="user">
        <!-- id:聲明主鍵,表示user_id是關聯查詢對象的唯一標識-->
        <id column="user_id" property="id"/>
        <result property="username" column="username"/>
        <result property="address" column="address"/>
    </association>
</resultMap>

<select id="queryOrderUseResultMap1" resultMap="orderUserResultMap" timeout="5000">
    select
        o.id,
        o.user_id,
        u.username,
        o.shopping_name,
        u.address
    from
        tb_order o
    left join
        tb_user u
    on
        o.user_id = u.id
</select>

4)寫測試代碼

 @Test
    public void testQueryOrderUseResultMap() {
        try {
            InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession sqlSession = sqlSessionFactory.openSession();

            OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);

            List<Order> orders = mapper.queryOrderUseResultMap1();
            for (Order order : orders) {
                System.out.println(order);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

5)結果

6.5.2 一對多

1)pojo改造

package cn.cyikns.pojo;

import java.io.Serializable;
import java.util.List;

/**
 * @author cyikns
 * @create 2018-08-07 18:49
 */
public class User implements Serializable {

    private int id;
    private String username;
    private String password;
    private String address;


    private List<Order> orders;

    public List<Order> getOrders() {
        return orders;
    }

    public void setOrders(List<Order> orders) {
        this.orders = orders;
    }

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", address='" + address + '\'' +
                ", orders=" + orders +
                '}';
    }
}

2)寫接口

List<User> queryUserAndOrders();

3)編寫UserMapper.xml

  <resultMap id="userOrderResultMap" type="user">
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <result property="address" column="address"/>
        <!--配置一對多關係-->
        <collection property="orders" javaType="list" ofType="order">
            <!-- 配置主鍵,是關聯Order的唯一標識 -->
            <id property="id" column="id"/>
            <result property="userId" column="user_id"/>
            <result property="shoppingName" column="shopping_name"/>
        </collection>

    </resultMap>

    <!-- 一對多關聯,查詢訂單同時查詢該用戶下的訂單 -->
    <select id="queryUserAndOrders" resultMap="userOrderResultMap" timeout="5000">
        select
            o.id,
            o.user_id,
            u.username,
            o.shopping_name,
            u.address
        from
            tb_user u
        left join
            tb_order o
        on
            o.user_id = u.id
    </select>

4)寫測試

@Test
    public void testQueryUserAndOrders() {
        try {
            InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession sqlSession = sqlSessionFactory.openSession();

            UserMapper mapper = sqlSession.getMapper(UserMapper.class);

            List<User> users = mapper.queryUserAndOrders();

            for (User user : users) {
                System.out.println(user);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

5)結果

後記

寫這篇日記差不多花了兩天時間,剛開始不是很熟悉,慢慢的就順暢一點了,在這裏總結下,建數據庫特別是主鍵最好是有所區分,比如User表主鍵用uid,Order表主鍵用oid,統一用id來表示很多時候會混淆到底哪個是哪個,表名字段儘量精簡表意。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章