Mybatis教程-實戰看這一篇就夠了

轉自:https://blog.csdn.net/hellozpc/article/details/80878563html

1.從JDBC談起

1.1.使用IDEA建立maven工程

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327200504300-1646561105.png" data-action="zoom"/> </div>java

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327200519165-262073418.png" data-action="zoom"/> </div>mysql

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327200526212-1288959203.png" data-action="zoom"/> </div>程序員

1.2.引入mysql依賴包

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

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327200538055-1190876723.png" data-action="zoom"/> </div>面試

1.3.準備數據

  • 建立數據庫:
CREATE DATABASE ssmdemo;
  • 建立表:
DROP TABLE IF EXISTS tb_user;
CREATE TABLE tb_user (
id char(32) NOT NULL,
user_name varchar(32) DEFAULT NULL,
password varchar(32) DEFAULT NULL,
name varchar(32) DEFAULT NULL,
age int(10) DEFAULT NULL,
sex int(2) DEFAULT NULL,
birthday date DEFAULT NULL,
created datetime DEFAULT NULL,
updated datetime DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  • 插入數據:
INSERT INTO ssmdemo.tb_user ( userName, password, name, age, sex, birthday, created, updated) VALUES ( ‘zpc’, ‘123456’, ‘鵬程’, ‘22’, ‘1’, ‘1990-09-02’, sysdate(), sysdate());
INSERT INTO ssmdemo.tb_user ( userName, password, name, age, sex, birthday, created, updated) VALUES ( ‘hj’, ‘123456’, ‘靜靜’, ‘22’, ‘1’, ‘1993-09-05’, sysdate(), sysdate());

1.4.JDBC基礎代碼回顧

  • JDBCTest.java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

/**
 * @author Evan
 */
public class JDBCTest {
    public static void main(String[] args) throws Exception {
        Connection connection = null;
        PreparedStatement prepareStatement = null;
        ResultSet rs = null;

        try {
            // 加載驅動
            Class.forName("com.mysql.jdbc.Driver");
            // 獲取鏈接
            String url = "jdbc:mysql://127.0.0.1:3306/ssmdemo";
            String user = "root";
            String password = "123456";
            connection = DriverManager.getConnection(url, user, password);
            // 獲取statement,preparedStatement
            String sql = "select * from tb_user where id=?";
            prepareStatement = connection.prepareStatement(sql);
            // 設置參數
            prepareStatement.setLong(1, 1l);
            // 執行查詢
            rs = prepareStatement.executeQuery();
            // 處理結果集
            while (rs.next()) {
                System.out.println(rs.getString("userName"));
                System.out.println(rs.getString("name"));
                System.out.println(rs.getInt("age"));
                System.out.println(rs.getDate("birthday"));
            }
        } finally {
            // 關閉鏈接,釋放資源
            if (rs != null) {
                rs.close();
            }
            if (prepareStatement != null) {
                prepareStatement.close();
            }
            if (connection != null) {
                connection.close();
            }
        }
    }
}

1.5.JDBC缺點分析

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327200758073-1117780956.png" data-action="zoom"/> </div>spring

2.MyBatis介紹

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327200810750-637756995.png" data-action="zoom"/> </div>sql

官方文檔 http://www.mybatis.org/mybatis-3/getting-started.html數據庫

3.Mybaits總體架構

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327200843495-1926482501.png" data-action="zoom"/> </div>apache

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327200855552-2120429717.png" data-action="zoom"/> </div>api

4.快速入門(quick start)

4.1.引入依賴(pom.xml)

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

4.2.全局配置文件(mybatis-config.xml)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 根標籤 -->
<configuration>
<properties>
	<property name="driver" value="com.mysql.jdbc.Driver"/>
	<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis-110?useUnicode=true&amp;characterEncoding=utf-8&amp;allowMultiQueries=true"/>
	<property name="username" value="root"/>
    	<property name="password" value="123456"/>
   </properties>

   <!-- 環境,能夠配置多個,default:指定採用哪一個環境 -->
   <environments default="test">
      <!-- id:惟一標識 -->
      <environment id="test">
         <!-- 事務管理器,JDBC類型的事務管理器 -->
         <transactionManager type="JDBC" />
         <!-- 數據源,池類型的數據源 -->
         <dataSource type="POOLED">
            <property name="driver" value="com.mysql.jdbc.Driver" />
            <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis-110" />
            <property name="username" value="root" />
            <property name="password" value="123456" />
         </dataSource>
      </environment>
      <environment id="development">
         <!-- 事務管理器,JDBC類型的事務管理器 -->
         <transactionManager type="JDBC" />
         <!-- 數據源,池類型的數據源 -->
         <dataSource type="POOLED">
            <property name="driver" value="${driver}" /> <!-- 配置了properties,因此能夠直接引用 -->
            <property name="url" value="${url}" />
            <property name="username" value="${username}" />
            <property name="password" value="${password}" />
         </dataSource>
      </environment>
   </environments>
  </configuration>

4.3.配置Map.xml(MyMapper.xml)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- mapper:根標籤,namespace:命名空間,隨便寫,通常保證命名空間惟一 -->
<mapper namespace="MyMapper">
   <!-- statement,內容:sql語句。id:惟一標識,隨便寫,在同一個命名空間下保持惟一
      resultType:sql語句查詢結果集的封裝類型,tb_user即爲數據庫中的表
    -->
   <select id="selectUser" resultType="com.zpc.mybatis.User">
      select * from tb_user where id = #{id}
   </select>
</mapper>

4.4.修改全局配置文件(mybatis-config.xml)

配上MyMapper.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>
   <!-- 環境,能夠配置多個,default:指定採用哪一個環境 -->
   <environments default="test">
      <!-- id:惟一標識 -->
      <environment id="test">
         <!-- 事務管理器,JDBC類型的事務管理器 -->
         <transactionManager type="JDBC" />
         <!-- 數據源,池類型的數據源 -->
         <dataSource type="POOLED">
            <property name="driver" value="com.mysql.jdbc.Driver" />
            <property name="url" value="jdbc:mysql://127.0.0.1:3306/ssmdemo" />
            <property name="username" value="root" />
            <property name="password" value="123456" />
         </dataSource>
      </environment>
   </environments>
   <mappers>
     <mapper resource="mappers/MyMapper.xml" />
   </mappers>
</configuration>

4.5.構建sqlSessionFactory(MybatisTest.java)

// 指定全局配置文件
        String resource = "mybatis-config.xml";
        // 讀取配置文件
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 構建sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

4.6.打開sqlSession會話,並執行sql(MybatisTest.java)

// 獲取sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 操做CRUD,第一個參數:指定statement,規則:命名空間+「.」+statementId
        // 第二個參數:指定傳入sql的參數:這裏是用戶id
        User user = sqlSession.selectOne("MyMapper.selectUser", 1);
        System.out.println(user);

完整代碼:

  • MybatisTest.java
mport com.zpc.test.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 java.io.InputStream;

public class MybatisTest {
   public static void main(String[] args) throws Exception {
      // 指定全局配置文件
      String resource = "mybatis-config.xml";
      // 讀取配置文件
      InputStream inputStream = Resources.getResourceAsStream(resource);
      // 構建sqlSessionFactory
      SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
      // 獲取sqlSession
      SqlSession sqlSession = sqlSessionFactory.openSession();
      try {
         // 操做CRUD,第一個參數:指定statement,規則:命名空間+「.」+statementId
         // 第二個參數:指定傳入sql的參數:這裏是用戶id
         User user = sqlSession.selectOne("MyMapper.selectUser", 1);
         System.out.println(user);
      } finally {
         sqlSession.close();
      }
   }
}
  • User.java
import java.text.SimpleDateFormat;
import java.util.Date;

public class User {
    private String id;
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private Integer sex;
    private Date birthday;
    private String created;
    private String updated;

    public String getId() {
        return id;
    }

    public void setId(String 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 getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getSex() {
        return sex;
    }

    public void setSex(Integer sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getCreated() {
        return created;
    }

    public void setCreated(String created) {
        this.created = created;
    }

    public String getUpdated() {
        return updated;
    }

    public void setUpdated(String updated) {
        this.updated = updated;
    }

    @Override
    public String toString() {
        return "User{" +
                "id='" + id + '\'' +
                ", userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", birthday='" + new SimpleDateFormat("yyyy-MM-dd").format(birthday) + '\'' +
                ", created='" + created + '\'' +
                ", updated='" + updated + '\'' +
                '}';
    }
}

4.7.目錄結構

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327201242155-412153999.png" data-action="zoom"/> </div>

5.分析

5.1.引入日誌依賴包(pom.xml)

會自動引入log4j以及slf4j-api

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.5</version>
</dependency>

5.2.添加log4j.properties

log4j.rootLogger=DEBUG,A1
log4j.logger.org.apache=DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n

再次運行程序會打印日誌:

2018-06-30 19:53:37,554 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Opening JDBC Connection
2018-06-30 19:53:37,818 [main] [org.apache.ibatis.datasource.pooled.PooledDataSource]-[DEBUG] Created connection 2094411587.
2018-06-30 19:53:37,818 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@7cd62f43]
2018-06-30 19:53:37,863 [main] [MyMapper.selectUser]-[DEBUG] ==>  Preparing: select * from tb_user where id = ? 
2018-06-30 19:53:37,931 [main] [MyMapper.selectUser]-[DEBUG] ==> Parameters: 1(Integer)
2018-06-30 19:53:37,953 [main] [MyMapper.selectUser]-[DEBUG] <==      Total: 1
User{id='1', userName='zpc', password='123456', name='鵬程', age=25, sex=1, birthday='1990-09-02', created='2018-06-30 18:20:18.0', updated='2018-06-30 18:20:18.0'}
2018-06-30 19:53:37,954 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@7cd62f43]
2018-06-30 19:53:37,954 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@7cd62f43]
2018-06-30 19:53:37,955 [main] [org.apache.ibatis.datasource.pooled.PooledDataSource]-[DEBUG] Returned connection 2094411587 to pool.

5.3.MyBatis使用步驟總結

  • 1)配置mybatis-config.xml 全局的配置文件 (一、數據源,二、外部的mapper)
  • 2)建立SqlSessionFactory
  • 3)經過SqlSessionFactory建立SqlSession對象
  • 4)經過SqlSession操做數據庫 CRUD
  • 5)調用session.commit()提交事務
  • 6)調用session.close()關閉會話

6.完整的CRUD操做

6.1.建立UserDao接口

import com.zpc.mybatis.pojo.User;
import java.util.List;

public interface UserDao {

    /**
     * 根據id查詢用戶信息
     *
     * @param id
     * @return
     */
    public User queryUserById(String id);

    /**
     * 查詢全部用戶信息
     *
     * @return
     */
    public List<User> queryUserAll();

    /**
     * 新增用戶
     *
     * @param user
     */
    public void insertUser(User user);

    /**
     * 更新用戶信息
     *
     * @param user
     */
    public void updateUser(User user);

    /**
     * 根據id刪除用戶信息
     *
     * @param id
     */
    public void deleteUser(String id);
}

6.2.建立UserDaoImpl

import com.zpc.mybatis.dao.UserDao;
import com.zpc.mybatis.pojo.User;
import org.apache.ibatis.session.SqlSession;
import java.util.List;

public class UserDaoImpl implements UserDao {
    public SqlSession sqlSession;

    public UserDaoImpl(SqlSession sqlSession) {
        this.sqlSession = sqlSession;
    }

    @Override
    public User queryUserById(String id) {
        return this.sqlSession.selectOne("UserDao.queryUserById", id);
    }

    @Override
    public List<User> queryUserAll() {
        return this.sqlSession.selectList("UserDao.queryUserAll");
    }

    @Override
    public void insertUser(User user) {
        this.sqlSession.insert("UserDao.insertUser", user);
    }

    @Override
    public void updateUser(User user) {
        this.sqlSession.update("UserDao.updateUser", user);
    }

    @Override
    public void deleteUser(String id) {
        this.sqlSession.delete("UserDao.deleteUser", id);
    }

}

6.3.編寫UserDao對應的UserDaoMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- mapper:根標籤,namespace:命名空間,隨便寫,通常保證命名空間惟一 -->
<mapper namespace="UserDao">
    <!-- statement,內容:sql語句。id:惟一標識,隨便寫,在同一個命名空間下保持惟一
       resultType:sql語句查詢結果集的封裝類型,tb_user即爲數據庫中的表
     -->
    <!--<select id="queryUserById" resultType="com.zpc.mybatis.pojo.User">-->
    <!--select * from tb_user where id = #{id}-->
    <!--</select>-->

    <!--使用別名-->
    <select id="queryUserById" resultType="com.zpc.mybatis.pojo.User">
      select
       tuser.id as id,
       tuser.user_name as userName,
       tuser.password as password,
       tuser.name as name,
       tuser.age as age,
       tuser.birthday as birthday,
       tuser.sex as sex,
       tuser.created as created,
       tuser.updated as updated
       from
       tb_user tuser
       where tuser.id = #{id};
   </select>

    <select id="queryUserAll" resultType="com.zpc.mybatis.pojo.User">
        select * from tb_user;
    </select>

    <!--插入數據-->
    <insert id="insertUser" parameterType="com.zpc.mybatis.pojo.User">
        INSERT INTO tb_user (
        user_name,
        password,
        name,
        age,
        sex,
        birthday,
        created,
        updated
        )
        VALUES
        (
        #{userName},
        #{password},
        #{name},
        #{age},
        #{sex},
        #{birthday},
        now(),
        now()
        );
    </insert>

    <update id="updateUser" parameterType="com.zpc.mybatis.pojo.User">
        UPDATE tb_user
        <trim prefix="set" suffixOverrides=",">
            <if test="userName!=null">user_name = #{userName},</if>
            <if test="password!=null">password = #{password},</if>
            <if test="name!=null">name = #{name},</if>
            <if test="age!=null">age = #{age},</if>
            <if test="sex!=null">sex = #{sex},</if>
            <if test="birthday!=null">birthday = #{birthday},</if>
            updated = now(),
        </trim>
        WHERE
        (id = #{id});
    </update>

    <delete id="deleteUser">
        delete from tb_user where id=#{id}
    </delete>
</mapper>

在mybatis-config.xml中添加配置:

<mappers>
    <mapper resource="mappers/MyMapper.xml"/>
    <mapper resource="mappers/UserDaoMapper.xml"/>
</mappers>

6.4.添加UserDao的測試用例

Pom文件中添加junit依賴

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

按住Alt+Enter,選擇create test

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327210035652-466296552.png" data-action="zoom"/> </div>

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327210053247-775730763.png" data-action="zoom"/> </div>

6.5.編寫UserDao的測試用例

import com.zpc.mybatis.dao.UserDao;
import com.zpc.mybatis.dao.impl.UserDaoImpl;
import com.zpc.mybatis.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.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

public class UserDaoTest {

    public UserDao userDao;
    public SqlSession sqlSession;

    @Before
    public void setUp() throws Exception {
        // mybatis-config.xml
        String resource = "mybatis-config.xml";
        // 讀取配置文件
        InputStream is = Resources.getResourceAsStream(resource);
        // 構建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        // 獲取sqlSession
        sqlSession = sqlSessionFactory.openSession();
        this.userDao = new UserDaoImpl(sqlSession);
    }

    @Test
    public void queryUserById() throws Exception {
        System.out.println(this.userDao.queryUserById("1"));
    }

    @Test
    public void queryUserAll() throws Exception {
        List<User> userList = this.userDao.queryUserAll();
        for (User user : userList) {
            System.out.println(user);
        }
    }

    @Test
    public void insertUser() throws Exception {
        User user = new User();
        user.setAge(16);
        user.setBirthday(new Date("1990/09/02"));
        user.setName("大鵬");
        user.setPassword("123456");
        user.setSex(1);
        user.setUserName("evan");
        this.userDao.insertUser(user);
        this.sqlSession.commit();
    }

    @Test
    public void updateUser() throws Exception {
        User user = new User();
        user.setBirthday(new Date());
        user.setName("靜鵬");
        user.setPassword("654321");
        user.setSex(1);
        user.setUserName("evanjin");
        user.setId("1");
        this.userDao.updateUser(user);
        this.sqlSession.commit();
    }

    @Test
    public void deleteUser() throws Exception {
        this.userDao.deleteUser("4");
        this.sqlSession.commit();
    }

}

6.6.目錄結構

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327210128990-270663855.png" data-action="zoom"/> </div>

6.7.解決數據庫字段名和實體類屬性名不一致的問題

查詢數據的時候,發現查不到userName的信息, User{id=‘2’, userName=‘null’, password=‘123456’, name=‘靜靜’, age=22, sex=0, birthday=‘1993-09-05’, created=‘2018-06-30 18:22:28.0’, updated=‘2018-06-30 18:22:28.0’} 緣由:數據庫的字段名是user_name,POJO中的屬性名字是userName 兩端不一致,形成mybatis沒法填充對應的字段信息。修改方法:在sql語句中使用別名。

  • 解決方案1:在sql語句中使用別名:
<select id="queryUserById" resultType="com.zpc.mybatis.pojo.User">
   select
    tuser.id as id,
    tuser.user_name as userName,
    tuser.password as password,
    tuser.name as name,
    tuser.age as age,
    tuser.birthday as birthday,
    tuser.sex as sex,
    tuser.created as created,
    tuser.updated as updated
    from
    tb_user tuser
    where tuser.id = #{id};
</select>
  • 解決方案2: 參考後面的resultMap –mapper具體的配置的時候

  • 解決方案3:參考駝峯匹配 — mybatis-config.xml 的時候

7.動態代理Mapper實現類

7.1.思考上述CRUD中的問題

  • 一、接口->實現類->mapper.xml
  • 二、實現類中,使用mybatis的方式很是相似
  • 三、xml中的sql statement 硬編碼到java代碼中。

思考:可否只寫接口,不寫實現類。只編寫接口和Mapper.xml便可?

由於在dao(mapper)的實現類中對sqlsession的使用方式很相似。所以mybatis提供了接口的動態代理。

7.2.使用動態代理改造CRUD

  • 修改測試用例的setUp方法

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327210330276-1518670435.png" data-action="zoom"/> </div>

  • 執行queryUserAll()方法

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327210338783-1518947660.png" data-action="zoom"/> </div>

org.apache.ibatis.binding.BindingException: Type interface com.zpc.mybatis.dao.UserDao is not known to the MapperRegistry.
	at org.apache.ibatis.binding.MapperRegistry.getMapper(MapperRegistry.java:47)
	at org.apache.ibatis.session.Configuration.getMapper(Configuration.java:655)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.getMapper(DefaultSqlSession.java:222)
at com.zpc.mybatis.test.UserDaoTest.setUp(UserDaoTest.java:32)
  • 分析緣由,在UserMapper.xml中配置接口的全路徑 mapper.xml namespace 若是但願使用mybatis經過的動態代理的接口,就須要namespace中的值,和須要對應的Mapper(dao)接口的全路徑一致。Mapper中Namespace的定義自己是沒有限制的,只要不重複便可,但若是使用Mybatis的DAO接口動態代理,則namespace必須爲DAO接口的全路徑,例如:com.zpc.mybatis.dao.UserDao
<mapper namespace="com.zpc.mybatis.dao.UserDao">

7.3.完整的例子

一、建立UserMapper接口(對應原UserDao)

public interface UserMapper {
   
   /**
    * 登陸(直接使用註解指定傳入參數名稱)
    * @param userName
    * @param password
    * @return
    */
   public User login(@Param("userName") String userName, @Param("password") String password);
   
   /**
    * 根據表名查詢用戶信息(直接使用註解指定傳入參數名稱)
    * @param tableName
    * @return
    */
   public List<User> queryUserByTableName(@Param("tableName") String tableName);
   
   /**
    * 根據Id查詢用戶信息
    * @param id
    * @return
    */
   public User queryUserById(Long id);
   
   /**
    * 查詢全部用戶信息
    * @return
    */
   public List<User> queryUserAll();
   
   /**
    * 新增用戶信息
    * @param user
    */
   public void insertUser(User user);
   
   /**
    * 根據id更新用戶信息
    * @param user
    */
   public void updateUser(User user);
   
   /**
    * 根據id刪除用戶信息
    * @param id
    */
   public void deleteUserById(Long id);
}

二、建立UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- mapper:根標籤,namespace:命名空間,隨便寫,通常保證命名空間惟一 ,爲了使用接口動態代理,這裏必須是接口的全路徑名-->
<mapper namespace="com.zpc.mybatis.dao.UserMapper">
    <!--
       1.#{},預編譯的方式preparedstatement,使用佔位符替換,防止sql注入,一個參數的時候,任意參數名能夠接收
       2.${},普通的Statement,字符串直接拼接,不能夠防止sql注入,一個參數的時候,必須使用${value}接收參數
     -->
    <select id="queryUserByTableName" resultType="com.zpc.mybatis.pojo.User">
        select * from ${tableName}
    </select>

    <select id="login" resultType="com.zpc.mybatis.pojo.User">
        select * from tb_user where user_name = #{userName} and password = #{password}
    </select>

    <!-- statement,內容:sql語句。
       id:惟一標識,隨便寫,在同一個命名空間下保持惟一,使用動態代理以後要求和方法名保持一致
       resultType:sql語句查詢結果集的封裝類型,使用動態代理以後和方法的返回類型一致;resultMap:二選一
       parameterType:參數的類型,使用動態代理以後和方法的參數類型一致
     -->
    <select id="queryUserById" resultType="com.zpc.mybatis.pojo.User">
        select * from tb_user where id = #{id}
    </select>
    <select id="queryUserAll" resultType="com.zpc.mybatis.pojo.User">
        select * from tb_user
    </select>
    <!-- 新增的Statement
       id:惟一標識,隨便寫,在同一個命名空間下保持惟一,使用動態代理以後要求和方法名保持一致
       parameterType:參數的類型,使用動態代理以後和方法的參數類型一致
       useGeneratedKeys:開啓主鍵回寫
       keyColumn:指定數據庫的主鍵
       keyProperty:主鍵對應的pojo屬性名
     -->
    <insert id="insertUser" useGeneratedKeys="true" keyColumn="id" keyProperty="id"
            parameterType="com.zpc.mybatis.pojo.User">
        INSERT INTO tb_user (
        id,
        user_name,
        password,
        name,
        age,
        sex,
        birthday,
        created,
        updated
        )
        VALUES
        (
        null,
        #{userName},
        #{password},
        #{name},
        #{age},
        #{sex},
        #{birthday},
        NOW(),
        NOW()
        );
    </insert>
    <!-- 
       更新的statement
       id:惟一標識,隨便寫,在同一個命名空間下保持惟一,使用動態代理以後要求和方法名保持一致
       parameterType:參數的類型,使用動態代理以後和方法的參數類型一致
     -->
    <update id="updateUser" parameterType="com.zpc.mybatis.pojo.User">
        UPDATE tb_user
        <trim prefix="set" suffixOverrides=",">
            <if test="userName!=null">user_name = #{userName},</if>
            <if test="password!=null">password = #{password},</if>
            <if test="name!=null">name = #{name},</if>
            <if test="age!=null">age = #{age},</if>
            <if test="sex!=null">sex = #{sex},</if>
            <if test="birthday!=null">birthday = #{birthday},</if>
            updated = now(),
        </trim>
        WHERE
        (id = #{id});
    </update>
    <!-- 
       刪除的statement
       id:惟一標識,隨便寫,在同一個命名空間下保持惟一,使用動態代理以後要求和方法名保持一致
       parameterType:參數的類型,使用動態代理以後和方法的參數類型一致
     -->
    <delete id="deleteUserById" parameterType="java.lang.String">
        delete from tb_user where id=#{id}
    </delete>
</mapper>

三、全局配置文件mybatis-config.xml引入UserMapper.xml

<mappers>
    <mapper resource="mappers/MyMapper.xml"/>
    <mapper resource="mappers/UserDaoMapper.xml"/>
    <mapper resource="mappers/UserMapper.xml"/>
</mappers>

四、建立UserMapper測試用例

import com.zpc.mybatis.dao.UserMapper;
import com.zpc.mybatis.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.Before;
import org.junit.Test;

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

public class UserMapperTest {

    public UserMapper userMapper;

    @Before
    public void setUp() throws Exception {
        // 指定配置文件
        String resource = "mybatis-config.xml";
        // 讀取配置文件
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 構建sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 獲取sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        // 1. 映射文件的命名空間(namespace)必須是mapper接口的全路徑
        // 2. 映射文件的statement的id必須和mapper接口的方法名保持一致
        // 3. Statement的resultType必須和mapper接口方法的返回類型一致
        // 4. statement的parameterType必須和mapper接口方法的參數類型一致(不必定)
        this.userMapper = sqlSession.getMapper(UserMapper.class);
    }

    @Test
    public void testQueryUserByTableName() {
        List<User> userList = this.userMapper.queryUserByTableName("tb_user");
        for (User user : userList) {
            System.out.println(user);
        }
    }

    @Test
    public void testLogin() {
        System.out.println(this.userMapper.login("hj", "123456"));
    }

    @Test
    public void testQueryUserById() {
        System.out.println(this.userMapper.queryUserById("1"));
    }

    @Test
    public void testQueryUserAll() {
        List<User> userList = this.userMapper.queryUserAll();
        for (User user : userList) {
            System.out.println(user);
        }
    }

    @Test
    public void testInsertUser() {
        User user = new User();
        user.setAge(20);
        user.setBirthday(new Date());
        user.setName("大神");
        user.setPassword("123456");
        user.setSex(2);
        user.setUserName("bigGod222");
        this.userMapper.insertUser(user);
        System.out.println(user.getId());
    }

    @Test
    public void testUpdateUser() {
        User user = new User();
        user.setBirthday(new Date());
        user.setName("靜靜");
        user.setPassword("123456");
        user.setSex(0);
        user.setUserName("Jinjin");
        user.setId("1");
        this.userMapper.updateUser(user);
    }

    @Test
    public void testDeleteUserById() {
        this.userMapper.deleteUserById("1");
    }
}

目錄結構:

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327210604115-981007217.png" data-action="zoom"/> </div>

7.4.動態代理總結

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327210614124-2167749.png" data-action="zoom"/> </div>

8.mybatis-config.xml詳解

mybatis-config.xml講究嚴格的順序,具體順序遵循文檔的順序

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327210626940-903705426.png" data-action="zoom"/> </div>

8.1.properties屬性讀取外部資源

properties配置的屬性都是可外部配置且可動態替換的,既能夠在典型的 Java 屬性文件中配置,亦可經過 properties 元素的子元素來傳遞。例如:

<properties resource="org/mybatis/example/config.properties">
  <property name="username" value="dev_user"/>
  <property name="password" value="F2Fa3!33TYyg"/>
</properties>

而後其中的屬性就能夠在整個配置文件中被用來替換須要動態配置的屬性值。好比:

<dataSource type="POOLED">
  <property name="driver" value="${driver}"/>
  <property name="url" value="${url}"/>
  <property name="username" value="${username}"/>
  <property name="password" value="${password}"/>
</dataSource>

這個例子中的 username 和 password 將會由 properties 元素中設置的相應值來替換。 driver 和 url 屬性將會由 config.properties 文件中對應的值來替換。這樣就爲配置提供了諸多靈活選擇。

屬性也能夠被傳遞到 SqlSessionFactoryBuilder.build()方法中。例如:

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props);
// ... or ...
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, props);

若是屬性在不僅一個地方進行了配置,那麼 MyBatis 將按照下面的順序來加載:

  • 1)在 properties 元素體內指定的屬性首先被讀取。
  • 2)而後根據 properties 元素中的 resource 屬性讀取類路徑下屬性文件或根據 url 屬性指定的路徑讀取屬性文件,並覆蓋已讀取的同名屬性。
  • 3)最後讀取做爲方法參數傳遞的屬性,並覆蓋已讀取的同名屬性。

所以,經過方法參數傳遞的屬性具備最高優先級,resource/url 屬性中指定的配置文件次之,最低優先級的是 properties 屬性中指定的屬性。

8.2.settings設置

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327210741776-205936991.png" data-action="zoom"/> </div>

<settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

測試: 沒有開啓駝峯匹配:

2018-07-01 13:57:56,486 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] ==>  Preparing: select * from tb_user where id = ? 
2018-07-01 13:57:56,524 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] ==> Parameters: 1(String)
2018-07-01 13:57:56,568 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] <==      Total: 1
User{id='1', userName='null', password='123456', name='大神', age=20, sex=2, birthday='2018-07-01', created='2018-07-01 13:36:09.0', updated='2018-07-01 13:36:09.0'}

開啓駝峯匹配:

2018-07-01 13:58:40,599 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] ==>  Preparing: select * from tb_user where id = ? 
2018-07-01 13:58:40,642 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] ==> Parameters: 1(String)
2018-07-01 13:58:40,661 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] <==      Total: 1
User{id='1', userName='bigGod222', password='123456', name='大神', age=20, sex=2, birthday='2018-07-01', created='2018-07-01 13:36:09.0', updated='2018-07-01 13:36:09.0'}

8.3.typeAliases 類型別名是爲 Java 類型命名的一個短的名字。它只和 XML 配置有關,存在的意義僅在於用來減小類徹底限定名的冗餘。

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

缺點:每一個pojo類都要去配置。 解決方案:使用掃描包,掃描指定包下的全部類,掃描以後的別名就是類名(不區分大小寫),建議使用的時候和類名一致。

<typeAliases>
    <!--type:實體類的全路徑。alias:別名,一般首字母大寫-->
    <!--<typeAlias type="com.zpc.mybatis.pojo.User" alias="User"/>-->
    <package name="com.zpc.mybatis.pojo"/>
</typeAliases>

Mybatis已經爲普通的 Java 類型內建了許多相應的類型別名。它們都是大小寫不敏感的.

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327210946024-1568261798.png" data-action="zoom"/> </div>

8.4.typeHandlers(類型處理器)

不管是 MyBatis 在預處理語句(PreparedStatement)中設置一個參數時,仍是從結果集中取出一個值時, 都會用類型處理器將獲取的值以合適的方式轉換成 Java 類型。能夠重寫類型處理器或建立你本身的類型處理器來處理不支持的或非標準的類型。

8.5.plugins(插件)攔截器

MyBatis 容許你在已映射語句執行過程當中的某一點進行攔截調用。默認狀況下,MyBatis 容許使用插件來攔截的方法調用包括:

Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)

ParameterHandler (getParameterObject, setParameters)

ResultSetHandler (handleResultSets, handleOutputParameters)

StatementHandler (prepare, parameterize, batch, update, query)

如今一些MyBatis 插件好比PageHelper都是基於這個原理,有時爲了監控sql執行效率,也可使用插件機制 原理:

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327211135308-2074954352.png" data-action="zoom"/> </div>

自定義攔截器:

// ExamplePlugin.java
@Intercepts({@Signature(
  type= Executor.class,
  method = "update",
  args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {
  public Object intercept(Invocation invocation) throws Throwable {
    return invocation.proceed();
  }
  public Object plugin(Object target) {
    return Plugin.wrap(target, this);
  }
  public void setProperties(Properties properties) {
  }
}

配置:

<!-- mybatis-config.xml -->
<plugins>
  <plugin interceptor="org.mybatis.example.ExamplePlugin">
    <property name="someProperty" value="100"/>
  </plugin>
</plugins>

上面的插件將會攔截在 Executor 實例中全部的 「update」 方法調用, 這裏的 Executor 是負責執行低層映射語句的內部對象。

8.6.environments(環境)

MyBatis 能夠配置成適應多種環境,例如,開發、測試和生產環境須要有不一樣的配置; 儘管能夠配置多個環境,每一個 SqlSessionFactory 實例只能選擇其一。 雖然,這種方式也能夠作到很方便的分離多個環境,可是實際使用場景下,咱們更多的是選擇使用spring來管理數據源,來作到環境的分離。

8.7.mappers

須要告訴 MyBatis 到哪裏去找到 SQL 映射語句。即告訴 MyBatis 到哪裏去找映射文件。你可使用相對於類路徑的資源引用, 或徹底限定資源定位符(包括 file:/// 的 URL),或類名和包名等。例如:

<!-- 使用相對於類路徑的資源引用 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>

<!-- 使用映射器接口實現類的徹底限定類名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>

這裏所謂的mapper接口路徑。實際上就是dao的接口路徑。在mybatis中,一般把dao的包叫作mapper。類名,也叫作mapper

  • 一、定義一個接口。
  • 二、在接口所在的包中定義mapper.xml,而且要求xml文件和interface的名稱要相同。
  • 三、在mybatis-config.xml 中經過class路徑,引入mapper(註解方式)。要求mapper.xml 中的名稱空間是類的接口的全路徑。

註解方式:

<mappers>
    <mapper resource="mappers/MyMapper.xml"/>
    <mapper resource="mappers/UserDaoMapper.xml"/>
    <!--註解方式可使用以下配置方式-->
    <mapper class="com.zpc.mybatis.dao.UserMapper"/>
</mappers>

問題:

  • 一、mapper.xml 和 java文件沒有分離。 以後的教程講述和spring整合以後解決。
  • 二、須要一個一個的去加載mapper。

固然也可使用包掃描(必須使用註解方式,即在接口方法上使用註解,如@Select("select * from tb_user ")): 缺點

  • 一、若是包的路徑有不少?
  • 二、mapper.xml和mapper.java沒有分離。 spring整合的時候解決。

9.Mapper XML文件詳解

9.1.CRUD標籤

9.1.1.select

select – 書寫查詢sql語句 select中的幾個屬性說明: id屬性:當前名稱空間下的statement的惟一標識。必須。要求id和mapper接口中的方法的名字一致。 resultType:將結果集映射爲java的對象類型。必須(和 resultMap 二選一) parameterType:傳入參數類型。能夠省略

9.1.2.insert

insert 的幾個屬性說明: id:惟一標識,隨便寫,在同一個命名空間下保持惟一,使用動態代理以後要求和方法名保持一致 parameterType:參數的類型,使用動態代理以後和方法的參數類型一致 useGeneratedKeys:開啓主鍵回寫 keyColumn:指定數據庫的主鍵 keyProperty:主鍵對應的pojo屬性名 標籤內部:具體的sql語句。

9.1.3.update

id屬性:當前名稱空間下的statement的惟一標識(必須屬性); parameterType:傳入的參數類型,能夠省略。 標籤內部:具體的sql語句。

9.1.4.delete

delete 的幾個屬性說明: id屬性:當前名稱空間下的statement的惟一標識(必須屬性); parameterType:傳入的參數類型,能夠省略。 標籤內部:具體的sql語句。

9.2.#{}和${}

場景:數據庫有兩個如出一轍的表。歷史表,當前表 查詢表中的信息,有時候從歷史表中去查詢數據,有時候須要去新的表去查詢數據。 但願使用1個方法來完成操做。

<select id="queryUserByTableName" resultType="com.zpc.mybatis.pojo.User">
    select * from #{tableName}
</select>

/**
 * 根據表名查詢用戶信息(直接使用註解指定傳入參數名稱)
 *
 * @param tableName
 * @return
 */
public List<User> queryUserByTableName(String tableName);

測試輸出:

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327211514143-697503265.png" data-action="zoom"/> </div>

有問題,報語法錯誤:至關於執行了這樣一條sql: select * from 「tb_user」; 顯然表名多了引號。

改正:

<select id="queryUserByTableName" resultType="com.zpc.mybatis.pojo.User">
    select * from ${tableName}
</select>

注意: #{} 只是替換?,至關於PreparedStatement使用佔位符去替換參數,能夠防止sql注入。 ${} 是進行字符串拼接,至關於sql語句中的Statement,使用字符串去拼接sql;$能夠是sql中的任一部分傳入到Statement中,不能防止sql注入。

使用${} 去取出參數值信息,須要使用${value} #{} 只是表示佔位,與參數的名字無關,若是隻有一個參數,會自動對應。

推薦:

/**
 * 根據表名查詢用戶信息(直接使用註解指定傳入參數名稱)
 *
 * @param tableName
 * @return
 */
public List<User> queryUserByTableName(@Param("tableName") String tableName);

<select id="queryUserByTableName" resultType="com.zpc.mybatis.pojo.User">
    select * from ${tableName}
</select>

#{}多個參數時:

/**
 * 登陸(直接使用註解指定傳入參數名稱)
 *
 * @param userName
 * @param password
 * @return
 */
public User login( String userName, String password);

<select id="login" resultType="com.zpc.mybatis.pojo.User">
    select * from tb_user where user_name = #{userName} and password = #{password}
</select>

報錯:

org.apache.ibatis.exceptions.PersistenceException: 
Error querying database.  Cause: org.apache.ibatis.binding.BindingException: Parameter 'userName' not found. Available parameters are [0, 1, param1, param2]
Cause: org.apache.ibatis.binding.BindingException: Parameter 'userName' not found. Available parameters are [0, 1, param1, param2]

解決方案一:

<select id="login" resultType="com.zpc.mybatis.pojo.User">
    select * from tb_user where user_name = #{0} and password = #{1}
</select>

解決方案二:

<select id="login" resultType="com.zpc.mybatis.pojo.User">
    select * from tb_user where user_name = #{param1} and password = #{param2}
</select>

最終解決方案:

/**
 * 登陸(直接使用註解指定傳入參數名稱)
 *
 * @param userName
 * @param password
 * @return
 */
public User login(@Param("userName") String userName, @Param("password") String password);

<select id="login" resultType="com.zpc.mybatis.pojo.User">
    select * from tb_user where user_name = #{userName} and password = #{password}
</select>

一般在方法的參數列表上加上一個註釋@Param(「xxxx」) 顯式指定參數的名字,而後經過${「xxxx」}或#{「xxxx」} sql語句動態生成的時候,使用${}; sql語句中某個參數進行佔位的時候#{}

9.3.面試題(#、$區別)

/**
 * #號
 * @param username1
 * @return
 */
User queryUserListByName1(@Param("username1") String username1);

/**
 * $號
 * @param username2
 * @return
 */
User queryUserListByName2(@Param("username2") String username2);

<select id="queryUserListByName1" resultType="com.zpc.mybatis.pojo.User">
    select * from tb_user WHERE user_name=#{username1}
</select>

<select id="queryUserListByName2" resultType="com.zpc.mybatis.pojo.User">
    select * from tb_user WHERE user_name='${username2}'//手動加了引號
</select>

9.4.resultMap

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327211835662-809178670.png" data-action="zoom"/> </div>

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327211845574-1504006745.png" data-action="zoom"/> </div>

使用:

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327211856049-978145666.png" data-action="zoom"/> </div>

9.5.sql片斷

<sql id=」」></sql>
<include refId=」」 />

例如在UserMapper.xml中定義以下片斷:

<sql id="commonSql">
		id,
			user_name,
			password,
			name,
			age,
			sex,
			birthday,
			created,
			updated	
</sql>

則能夠在UserMapper.xml中使用它:

<select id="queryUserById" resultMap="userResultMap">
	select <include refid="commonSql"></include> from tb_user where id = #{id}
</select>

<select id="queryUsersLikeUserName" resultType="User">
	select <include refid="commonSql"></include> from tb_user where user_name like "%"#{userName}"%"
</select>

Sql片斷也能夠定義在單獨的.xml文件中如: 定義CommonSQL.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="CommonSQL">
	<sql id="commonSql">
		id,
			user_name,
			password,
			name,
			age,
			sex,
			birthday,
			created,
			updated	
	</sql>
</mapper>

使用:

<select id="queryUserById" resultMap="userResultMap">
		select <include refid="CommonSQL.commonSql"></include> from tb_user where id = #{id}
	</select>
	
	<select id="queryUsersLikeUserName" resultType="User">
		select <include refid="CommonSQL.commonSql"></include> from tb_user where user_name like "%"#{userName}"%"
	</select>

固然要完成這個功能還須要在全局配置文件mybatis-config.xml中引入該外部配置文件:

<mappers>
		<mapper resource="CommonSQL.xml"/>
		<!-- 開啓mapper接口的包掃描,基於class的配置方式 -->
		<package name="com.zpc.mybatis.mapper"/>
</mappers>

10.動態sql

場景:查詢男性用戶,若是輸入了姓名,按姓名模糊查詢

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327212009653-1972719612.png" data-action="zoom"/> </div>

10.1.if

場景:查詢男性用戶,若是輸入了姓名,則按姓名查詢

定義接口:

/**
 * 查詢男性用戶,若是輸入了姓名,則按姓名查詢
 * @param name
 * @return
 */
List<User> queryUserList(@Param("name") String name);

編寫mapper

<select id="queryUserList" resultType="com.zpc.mybatis.pojo.User">
    select * from tb_user WHERE sex=1
    <if test="name!=null and name.trim()!=''">
      and name like '%${name}%'
    </if>
</select>

測試

@Test
public void testqueryUserList() {
    List<User> users = this.userMapper.queryUserList(null);
    for (User user : users) {
        System.out.println(user);
    }
}

10.2.choose when otherwise

場景:查詢男性用戶,若是輸入了姓名則按照姓名模糊查找,不然若是輸入了年齡則按照年齡查找,不然查找姓名爲「鵬程」的用戶。

定義接口:

/**
 * 查詢男性用戶,若是輸入了姓名則按照姓名模糊查找,不然若是輸入了年齡則按照年齡查找,不然查找姓名爲「鵬程」的用戶。
 * @param name
 * @param age
 * @return
 */
List<User> queryUserListByNameOrAge(@Param("name") String name,@Param("age") Integer age);

編寫mapper配置:

<select id="queryUserListByNameOrAge" resultType="com.zpc.mybatis.pojo.User">
    select * from tb_user WHERE sex=1
    <!--
    1.一旦有條件成立的when,後續的when則不會執行
    2.當全部的when都不執行時,纔會執行otherwise
    -->
    <choose>
        <when test="name!=null and name.trim()!=''">
            and name like '%${name}%'
        </when>
        <when test="age!=null">
            and age = #{age}
        </when>
        <otherwise>
            and name='鵬程'
        </otherwise>
    </choose>
</select>

測試:

@Test
public void queryUserListByNameOrAge() throws Exception {
    List<User> users = this.userMapper.queryUserListByNameOrAge(null, 16);
    for (User user : users) {
        System.out.println(user);
    }
}

10.3.where 和set

場景一:查詢全部用戶,若是輸入了姓名按照姓名進行模糊查詢,若是輸入年齡,按照年齡進行查詢,若是二者都輸入,兩個條件都要成立。

接口:

/**
 * 查詢全部用戶,若是輸入了姓名按照姓名進行模糊查詢,若是輸入年齡,按照年齡進行查詢,若是二者都輸入,兩個條件都要成立
 * @param name
 * @param age
 * @return
 */
List<User> queryUserListByNameAndAge(@Param("name") String name,@Param("age") Integer age);

配置:

<select id="queryUserListByNameAndAge" resultType="com.zpc.mybatis.pojo.User">
    select * from tb_user
    <!--若是多出一個and,會自動去除,若是缺乏and或者多出多個and則會報錯-->
    <where>
        <if test="name!=null and name.trim()!=''">
            and name like '%${name}%'
        </if>
        <if test="age!=null">
            and age = #{age}
        </if>
    </where>
</select>

測試:

@Test
public void queryUserListByNameAndAge() throws Exception {
    List<User> users = this.userMapper.queryUserListByNameAndAge("鵬程", 20);
    for (User user : users) {
        System.out.println(user);
    }
}

場景二:修改用戶信息,若是參數user中的某個屬性爲null,則不修改。 接口:

/**
 * 根據id更新用戶信息
 *
 * @param user
 */
public void updateUser(User user);

配置:

<update id="updateUser" parameterType="com.zpc.mybatis.pojo.User">
    UPDATE tb_user
    <trim prefix="set" suffixOverrides=",">
        <if test="userName!=null">user_name = #{userName},</if>
        <if test="password!=null">password = #{password},</if>
        <if test="name!=null">name = #{name},</if>
        <if test="age!=null">age = #{age},</if>
        <if test="sex!=null">sex = #{sex},</if>
        <if test="birthday!=null">birthday = #{birthday},</if>
        updated = now(),
    </trim>
    WHERE
    (id = #{id});
</update>

測試:

@Test
public void testUpdateUser() {
    User user = new User();
    user.setBirthday(new Date());
    user.setName("靜靜");
    user.setPassword("123456");
    user.setSex(0);
    user.setUserName("Jinjin");
    user.setId("1");
    this.userMapper.updateUser(user);
}

10.4.foreach

場景:按照多個id查詢用戶信息

接口:

/**
 * 按多個Id查詢
 * @param ids
 * @return
 */
List<User> queryUserListByIds(@Param("ids") String[] ids);

配置:

<select id="queryUserListByIds" resultType="com.zpc.mybatis.pojo.User">
    select * from tb_user where id in
    <foreach collection="ids" item="id" open="(" close=")" separator=",">
        #{id}
    </foreach>
</select>

測試:

@Test
public void queryUserListByIds() throws Exception {
    List<User> users = this.userMapper.queryUserListByIds(new String[]{"1","2"});
    for (User user : users) {
        System.out.println(user);
    }
}

If:testognl表達式或者簡單java代碼 Choose when otherwise—>至關於if else if else When test參考if Where set 都有必定的糾錯功能 Trim:prefix suffix prefixOverrides suffixOverrides Foreach:collection item saparator open close

11.緩存

11.1.一級緩存

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327212328474-39938392.png" data-action="zoom"/> </div>

在mybatis中,一級緩存默認是開啓的,而且一直沒法關閉

一級緩存知足條件:

  • 一、同一個session中
  • 二、相同的SQL和參數

測試:

@Test
public void testQueryUserById() {
    System.out.println(this.userMapper.queryUserById("1"));
    System.out.println(this.userMapper.queryUserById("1"));
}
2018-07-01 17:08:50,156 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Opening JDBC Connection
2018-07-01 17:08:50,421 [main] [org.apache.ibatis.datasource.pooled.PooledDataSource]-[DEBUG] Created connection 242355057.
2018-07-01 17:08:50,423 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] ==>  Preparing: select * from tb_user where id = ? 
2018-07-01 17:08:50,476 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] ==> Parameters: 1(String)
2018-07-01 17:08:50,509 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] <==      Total: 1
User{id='1', userName='bigGod222', password='123456', name='鵬程', age=20, sex=1, birthday='2018-07-01', created='2018-07-01 13:35:40.0', updated='2018-07-01 13:35:40.0'}
User{id='1', userName='bigGod222', password='123456', name='鵬程', age=20, sex=1, birthday='2018-07-01', created='2018-07-01 13:35:40.0', updated='2018-07-01 13:35:40.0'}

使用:sqlSession.clearCache();能夠強制清除緩存

測試:

@Test
public void testQueryUserById() {
    System.out.println(this.userMapper.queryUserById("1"));
    sqlSession.clearCache();
    System.out.println(this.userMapper.queryUserById("1"));
}

日誌:

2018-07-01 17:10:51,065 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Opening JDBC Connection
2018-07-01 17:10:51,359 [main] [org.apache.ibatis.datasource.pooled.PooledDataSource]-[DEBUG] Created connection 242355057.
2018-07-01 17:10:51,360 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] ==>  Preparing: select * from tb_user where id = ? 
2018-07-01 17:10:51,408 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] ==> Parameters: 1(String)
2018-07-01 17:10:51,437 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] <==      Total: 1
User{id='1', userName='bigGod222', password='123456', name='鵬程', age=20, sex=1, birthday='2018-07-01', created='2018-07-01 13:35:40.0', updated='2018-07-01 13:35:40.0'}
2018-07-01 17:10:51,438 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] ==>  Preparing: select * from tb_user where id = ? 
2018-07-01 17:10:51,438 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] ==> Parameters: 1(String)
2018-07-01 17:10:51,440 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] <==      Total: 1
User{id='1', userName='bigGod222', password='123456', name='鵬程', age=20, sex=1, birthday='2018-07-01', created='2018-07-01 13:35:40.0', updated='2018-07-01 13:35:40.0'}

執行update、insert、delete的時候,會清空緩存 測試:

@Test
public void testQueryUserById() {
    System.out.println(this.userMapper.queryUserById("1"));
    //sqlSession.clearCache();

    User user=new User();
    user.setName("美女");
    user.setId("1");
    userMapper.updateUser(user);

    System.out.println(this.userMapper.queryUserById("1"));
}

日誌:

2018-07-01 17:18:15,128 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Opening JDBC Connection
2018-07-01 17:18:15,399 [main] [org.apache.ibatis.datasource.pooled.PooledDataSource]-[DEBUG] Created connection 242355057.
2018-07-01 17:18:15,401 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] ==>  Preparing: select * from tb_user where id = ? 
2018-07-01 17:18:15,466 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] ==> Parameters: 1(String)
2018-07-01 17:18:15,492 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] <==      Total: 1
User{id='1', userName='bigGod222', password='123456', name='鵬程', age=20, sex=1, birthday='2018-07-01', created='2018-07-01 13:35:40.0', updated='2018-07-01 13:35:40.0'}
2018-07-01 17:18:15,527 [main] [com.zpc.mybatis.dao.UserMapper.updateUser]-[DEBUG] ==>  Preparing: UPDATE tb_user set name = ?, updated = now() WHERE (id = ?); 
2018-07-01 17:18:15,529 [main] [com.zpc.mybatis.dao.UserMapper.updateUser]-[DEBUG] ==> Parameters: 美女(String), 1(String)
2018-07-01 17:18:15,532 [main] [com.zpc.mybatis.dao.UserMapper.updateUser]-[DEBUG] <==    Updates: 1
2018-07-01 17:18:15,532 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] ==>  Preparing: select * from tb_user where id = ? 
2018-07-01 17:18:15,533 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] ==> Parameters: 1(String)
2018-07-01 17:18:15,538 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] <==      Total: 1
User{id='1', userName='bigGod222', password='123456', name='美女', age=20, sex=1, birthday='2018-07-01', created='2018-07-01 13:35:40.0', updated='2018-07-01 17:18:15.0'}

11.2.二級緩存

mybatis 的二級緩存的做用域是一個mapper的namespace ,同一個namespace中查詢sql能夠從緩存中命中。

開啓二級緩存:

<mapper namespace="com.zpc.mybatis.dao.UserMapper">
    <cache/>
</mapper>

測試:

@Test
public void testCache() {
    System.out.println(this.userMapper.queryUserById("1"));

    sqlSession.close();
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    System.out.println(mapper.queryUserById("1"));
}

開啓二級緩存,必須序列化:

public class User implements Serializable{
    private static final long serialVersionUID = -3330851033429007657L;

日誌:

2018-07-01 17:23:39,335 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Opening JDBC Connection
2018-07-01 17:23:39,664 [main] [org.apache.ibatis.datasource.pooled.PooledDataSource]-[DEBUG] Created connection 2092769598.
2018-07-01 17:23:39,665 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] ==>  Preparing: select * from tb_user where id = ? 
2018-07-01 17:23:39,712 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] ==> Parameters: 1(String)
2018-07-01 17:23:39,734 [main] [com.zpc.mybatis.dao.UserMapper.queryUserById]-[DEBUG] <==      Total: 1
User{id='1', userName='bigGod222', password='123456', name='美女', age=20, sex=1, birthday='2018-07-01', created='2018-07-01 13:35:40.0', updated='2018-07-01 17:18:15.0'}
2018-07-01 17:23:39,743 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-[DEBUG] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@7cbd213e]
2018-07-01 17:23:39,744 [main] [org.apache.ibatis.datasource.pooled.PooledDataSource]-[DEBUG] Returned connection 2092769598 to pool.
2018-07-01 17:23:39,746 [main] [com.zpc.mybatis.dao.UserMapper]-[DEBUG] Cache Hit Ratio [com.zpc.mybatis.dao.UserMapper]: 0.5
User{id='1', userName='bigGod222', password='123456', name='美女', age=20, sex=1, birthday='2018-07-01', created='2018-07-01 13:35:40.0', updated='2018-07-01 17:18:15.0'}

關閉二級緩存: 不開啓,或者在全局的mybatis-config.xml 中去關閉二級緩存

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327212552002-822315719.png" data-action="zoom"/> </div>

<settings>
    <!--開啓駝峯匹配-->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
    <!--開啓二級緩存,全局總開關,這裏關閉,mapper中開啓了也沒用-->
    <setting name="cacheEnabled" value="false"/>
</settings>

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327212624115-192688159.png" data-action="zoom"/> </div>

12.高級查詢

12.1.表關係說明

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327212637757-1187600919.png" data-action="zoom"/> </div>

建立order表:

CREATE TABLE tb_order (
id int(11) NOT NULL AUTO_INCREMENT,
user_id int(11) DEFAULT NULL,
order_number varchar(255) DEFAULT NULL,
create datetime DEFAULT NULL,
updated datetime DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
public class Order {
    private Integer id;
    private Long userId;
    private String orderNumber;
    private Date created;
    private Date updated;
}

需求說明:

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327212707392-647036765.png" data-action="zoom"/> </div>

12.2.一對一查詢

  • 方法一:核心思想擴展Order對象,來完成映射 新建OrderUser實體類繼承Order:
public class OrderUser extends Order {
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private Integer sex;
    private Date birthday;
    private Date created;
    private Date updated;
}

OrderMapper接口:

public interface OrderMapper {
     OrderUser queryOrderUserByOrderNumber(@Param("number") String number);
}

配置OrderMapper:

<mapper namespace="com.zpc.mybatis.dao.OrderMapper">
    <select id="queryOrderUserByOrderNumber" resultType="com.zpc.mybatis.pojo.OrderUser">
      select * from tb_order o left join tb_user u on o.user_id=u.id where o.order_number = #{number}
   </select>
</mapper>

測試:

@Test
public void queryOrderUserByOrderNumber() throws Exception {
    OrderUser orderUser = orderMapper.queryOrderUserByOrderNumber("201807010001");
    System.out.println(orderUser);
}
  • 方法二:面向對象的思想,在Order對象中添加User對象。

在Order對象中添加User屬性:

public class Order {
    private Integer id;
    private Long userId;
    private String orderNumber;
    private Date created;
    private Date updated;
    private User user;
}

接口:

/**
 * 根據訂單號查詢訂單用戶的信息
 * @param number
 * @return
 */
Order queryOrderWithUserByOrderNumber(@Param("number") String number);

使用resultType不能完成自動映射,須要手動完成結果集映射resultMap:

<resultMap id="OrderUserResultMap" type="com.zpc.mybatis.pojo.Order" autoMapping="true">
     <id column="id" property="id"/>
     <!--association:完成子對象的映射-->
     <!--property:子對象在父對象中的屬性名-->
     <!--javaType:子對象的java類型-->
     <!--autoMapping:完成子對象的自動映射,若開啓駝峯,則按駝峯匹配-->
     <association property="user" javaType="com.zpc.mybatis.pojo.User" autoMapping="true">
         <id column="user_id" property="id"/>
     </association>
 </resultMap>

 <select id="queryOrderWithUserByOrderNumber" resultMap="OrderUserResultMap">
   select * from tb_order o left join tb_user u on o.user_id=u.id where o.order_number = #{number}
</select>

測試:

@Test
public void queryOrderWithUserByOrderNumber() throws Exception {
    Order order = orderMapper.queryOrderWithUserByOrderNumber("201807010001");
    System.out.println(order.getUser());
}

12.3.一對多查詢

一對多查詢:查詢訂單,查詢出下單人信息而且查詢出訂單詳情。

Order類:

public class Order {
    private Integer id;
    private Long userId;
    private String orderNumber;
    private Date created;
    private Date updated;
    private User user;
    private List<OrderDetail> detailList;
}
public class OrderDetail {
    private Integer id;
    private Integer orderId;
    private Double totalPrice;
    private Integer status;
}

接口:

/**
 * 根據訂單號查詢訂單用戶的信息及訂單詳情
 * @param number
 * @return
 */
Order queryOrderWithUserAndDetailByOrderNumber(@Param("number") String number);

Mapper映射:

<resultMap id="OrderUserDetailResultMap" type="com.zpc.mybatis.pojo.Order" autoMapping="true">
    <id column="id" property="id"/>
    <!--collection:定義子對象集合映射-->
    <!--association:完成子對象的映射-->
    <!--property:子對象在父對象中的屬性名-->
    <!--javaType:子對象的java類型-->
    <!--autoMapping:完成子對象的自動映射,若開啓駝峯,則按駝峯匹配-->
    <association property="user" javaType="com.zpc.mybatis.pojo.User" autoMapping="true">
        <id column="user_id" property="id"/>
    </association>
    <collection property="detailList" javaType="List" ofType="com.zpc.mybatis.pojo.OrderDetail" autoMapping="true">
        <id column="id" property="id"/>
    </collection>
</resultMap>

 <select id="queryOrderWithUserAndDetailByOrderNumber" resultMap="OrderUserDetailResultMap">
   select * from tb_order o
   left join tb_user u on o.user_id=u.id
   left join tb_orderdetail od on o.id=od.order_id
   where o.order_number = #{number}
</select>

測試:

@Test
public void queryOrderWithUserAndDetailByOrderNumber() throws Exception {
    Order order = orderMapper.queryOrderWithUserAndDetailByOrderNumber("201807010001");
    System.out.println(order.getUser());
    System.out.println(order.getDetailList());
}

12.4.多對多查詢

多對多查詢:查詢訂單,查詢出下單人信息而且查詢出訂單詳情中的商品數據。

OrderDetail類

public class OrderDetail {
    private Integer id;
    private Integer orderId;
    private Double totalPrice;
    private Integer status;
    private Item item;
}

public class Item {
    private Integer id;
    private String itemName;
    private Float itemPrice;
    private String itemDetail;
}

接口:

/**
 * 根據訂單號查詢訂單用戶的信息及訂單詳情及訂單詳情對應的商品信息
 * @param number
 * @return
 */
Order queryOrderWithUserAndDetailItemByOrderNumber(@Param("number") String number);

Mapper配置:

<resultMap id="OrderUserDetailItemResultMap" type="com.zpc.mybatis.pojo.Order" autoMapping="true">
    <id column="id" property="id"/>
    <association property="user" javaType="com.zpc.mybatis.pojo.User" autoMapping="true">
        <id column="user_id" property="id"/>
    </association>
    <collection property="detailList" javaType="List" ofType="com.zpc.mybatis.pojo.OrderDetail" autoMapping="true">
        <id column="detail_id" property="id"/>
        <association property="item" javaType="com.zpc.mybatis.pojo.Item" autoMapping="true">
            <id column="item_id" property="id"/>
        </association>
    </collection>
</resultMap>

 <select id="queryOrderWithUserAndDetailItemByOrderNumber" resultMap="OrderUserDetailItemResultMap">
   select * ,od.id as detail_id from tb_order o
   left join tb_user u on o.user_id=u.id
   left join tb_orderdetail od on o.id=od.order_id
   left join tb_item i on od.item_id=i.id
   where o.order_number = #{number}
</select>

測試:

@Test
public void queryOrderWithUserAndDetailItemByOrderNumber() throws Exception {
    Order order = orderMapper.queryOrderWithUserAndDetailItemByOrderNumber("201807010001");
    System.out.println(order);
    System.out.println(order.getUser());
    System.out.println(order.getDetailList());
}

至此,目錄結構以下:

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213011262-187994203.png" data-action="zoom"/> </div>

數據庫腳本:

CREATE TABLE tb_order (
id int(11) NOT NULL AUTO_INCREMENT,
user_id int(11) DEFAULT NULL,
order_number varchar(255) DEFAULT NULL,
create datetime DEFAULT NULL,
updated datetime DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO tb_order VALUES (‘1’, ‘2’, ‘201807010001’, ‘2018-07-01 19:38:35’, ‘2018-07-01 19:38:40’);

CREATE TABLE tb_item (
id int(11) NOT NULL,
itemName varchar(255) DEFAULT NULL,
itemPrice decimal(10,2) DEFAULT NULL,
itemDetail varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO tb_item VALUES (‘1’, ‘襪子’, ‘29.90’, ‘香香的襪子’);
INSERT INTO tb_item VALUES (‘2’, ‘套子’, ‘99.99’, ‘岡本001’);

CREATE TABLE tb_orderdetail (
id int(11) NOT NULL AUTO_INCREMENT,
order_id int(11) DEFAULT NULL,
total_price decimal(10,0) DEFAULT NULL,
item_id int(11) DEFAULT NULL,
status int(10) unsigned zerofill DEFAULT NULL COMMENT ‘0成功非0失敗’,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO tb_orderdetail VALUES (‘1’, ‘1’, ‘10000’, ‘1’, ‘0000000001’);
INSERT INTO tb_orderdetail VALUES (‘2’, ‘1’, ‘2000’, ‘2’, ‘0000000000’);

12.5.resultMap的繼承

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213033567-524075282.png" data-action="zoom"/> </div>

12.6.高級查詢的整理

resutlType沒法幫助咱們自動的去完成映射,因此只有使用resultMap手動的進行映射 type 結果集對應的數據類型 id 惟一標識,被引用的時候,進行指定

<resultMap type="Order" id="orderUserLazyResultMap">
<!—定義pojo中的單個對象的 property 定義對象的屬性名, javaType 屬性的類型,
		<association property="user" javaType="User" autoMapping="true">
			<id />
		</association>
<!—若是屬性是集合使用collection ,javaType 集合的類型,ofType 表示集中的存儲的元素類型
		<collection property="details" javaType="List" ofType="OrderDetail" autoMapping="true">
			<id />
</resultMap>

13.延遲加載

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213056781-2123378253.png" data-action="zoom"/> </div>

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213106661-1922033930.png" data-action="zoom"/> </div>

編寫接口:

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213114124-929868016.png" data-action="zoom"/> </div>

Mapper配置:

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213119750-347704220.png" data-action="zoom"/> </div>

測試:

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213125710-1329533891.png" data-action="zoom"/> </div>

結果:

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213132477-2014481028.png" data-action="zoom"/> </div>

開啓延遲加載:

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213138512-1029470318.png" data-action="zoom"/> </div>

修改測試用例:

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213143588-1875273495.png" data-action="zoom"/> </div>

執行,報錯:

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213149122-78518621.png" data-action="zoom"/> </div>

添加cglib:

<dependency>
		<groupId>cglib</groupId>
		<artifactId>cglib</artifactId>
		<version>3.1</version>
</dependency>

執行:

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213209754-1677238424.png" data-action="zoom"/> </div>

14.若是sql語句中出現’<’的解決方案

一、使用xml中的字符實體

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213221528-1107290735.png" data-action="zoom"/> </div>

由於業務,須要在mybatis中,使用到大於號,小於號,因此就在SQL中直接使用了。 SELECT * FROM test WHERE 1 = 1 AND start_date <= CURRENT_DATE AND end_date >= CURRENT_DATE 但是,在執行時,總報錯誤:

Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 74; columnNumber: 17;

元素內容必須由格式正確的字符數據或標記組成。 把AND start_date >= CURRENT_DATE AND end_date <= CURRENT_DATE去掉,就沒有問題,因此肯定是由於大於號,小於號引發的問題。

因而就想到了特殊符號,因而用了轉義字符把>和<替換掉,而後就沒有問題了。 SELECT * FROM test WHERE 1 = 1 AND start_date &lt;= CURRENT_DATE AND end_date &gt;= CURRENT_DATE 案例:

1.<if test="startDateTime!=null"> and mm.ttime &gt; to_date(#{startDateTime},'yyyy-mm-dd hh24:mi:ss')</if>  
2.<if test="endDateTime!=null"> and mm.ttime &lt;= to_date(#{endDateTime},'yyyy-mm-dd hh24:mi:ss')</if>

二、使用<![CDATA[ < ]]>

案例1:

1.<![CDATA[ 
2.       and mm.ttime > to_date(#{startDateTime},'yyyy-mm-dd hh24:mi:ss') 
3.       and mm.ttime <= to_date(#{endDateTime},'yyyy-mm-dd hh24:mi:ss') 
4.]]>

案例2:

mapper文件示例代碼 :

and (t1.status <![CDATA[ >= ]]> 1  and  t1.status <![CDATA[ <= ]]> 2)
上述代碼其實對應的sql:
and (t1.status > =1 andt1.status <= 2)

注意:

使用<![CDATA[ ]]>標記的sql語句中的<where> <if>等標籤不會被解析。

15.Spring 集成Mybatis

15.1引入spring和Mybatis相關依賴

pom.xml

<!--數據庫鏈接池-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.8</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.2.2</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.1.3.RELEASE</version>
</dependency>
<!--spring集成Junit測試-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.1.3.RELEASE</version>
    <scope>test</scope>
</dependency>
<!--spring容器-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.1.3.RELEASE</version>
</dependency>

15.2配置spring配置文件

applicationContext-dao.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
   http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

    <!-- 加載配置文件 -->
    <context:property-placeholder location="classpath:properties/*.properties"/>
    <!-- 數據庫鏈接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
          destroy-method="close">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url"
                  value="jdbc:mysql://${jdbc.host}:3306/${jdbc.database}?useUnicode=true&amp;characterEncoding=utf-8&amp;zeroDateTimeBehavior=convertToNull"/>
        <property name="username" value="${jdbc.userName}"/>
        <property name="password" value="${jdbc.passWord}"/>
        <!-- 初始化鏈接大小 -->
        <property name="initialSize" value="${jdbc.initialSize}"></property>
        <!-- 鏈接池最大數據庫鏈接數  0 爲沒有限制 -->
        <property name="maxActive" value="${jdbc.maxActive}"></property>
        <!-- 鏈接池最大的空閒鏈接數,這裏取值爲20,表示即便沒有數據庫鏈接時依然能夠保持20空閒的鏈接,而不被清除,隨時處於待命狀態 0 爲沒有限制 -->
        <property name="maxIdle" value="${jdbc.maxIdle}"></property>
        <!-- 鏈接池最小空閒 -->
        <property name="minIdle" value="${jdbc.minIdle}"></property>
        <!--最大創建鏈接等待時間。若是超過此時間將接到異常。設爲-1表示無限制-->
        <property name="maxWait" value="${jdbc.maxWait}"></property>
    </bean>

    <!-- spring和MyBatis完美整合 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!-- 自動掃描mapping.xml文件 -->
        <property name="mapperLocations" value="classpath:mappers/*.xml"></property>
        <!--若是mybatis-config.xml沒有特殊配置也能夠不須要下面的配置-->
        <property name="configLocation" value="classpath:mybatis-config.xml" />
    </bean>

    <!-- DAO接口所在包名,Spring會自動查找其下的類 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.zpc.mybatis.dao"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
    </bean>

    <!-- (事務管理)transaction manager -->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>

db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.host=localhost
jdbc.database=ssmdemo
jdbc.userName=root
jdbc.passWord=123456
jdbc.initialSize=0
jdbc.maxActive=20
jdbc.maxIdle=20
jdbc.minIdle=1
jdbc.maxWait=1000

因爲applicationContext-dao.xml中配置了Mapper接口掃描,因此刪除mybatis-config.xml中的配置,不然報已映射錯誤: Caused by: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. Cause: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for MyMapper.selectUser 刪除mybatis-config.xml中的映射配置:

<!--<mappers>-->
    <!--<mapper resource="mappers/MyMapper.xml"/>-->
    <!--<mapper resource="mappers/UserDaoMapper.xml"/>-->
    <!--<mapper resource="mappers/UserMapper.xml"/>-->
    <!--<mapper resource="mappers/OrderMapper.xml"/>-->
<!--</mappers>-->

或者在構建sqlSessionFactory時不配置mybatis-config.xml也行:

<!-- spring和MyBatis完美整合 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <!-- 自動掃描mapping.xml文件 -->
    <property name="mapperLocations" value="classpath:mappers/*.xml"></property>
    <!--若是mybatis-config.xml沒有特殊配置也能夠不須要下面的配置-->
    <!--<property name="configLocation" value="classpath:mybatis-config.xml" />-->
</bean>

15.3 測試

UserMapperSpringTest.java

import com.zpc.mybatis.dao.UserMapper;
import com.zpc.mybatis.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.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

//目標:測試一下spring的bean的某些功能
@RunWith(SpringJUnit4ClassRunner.class)//junit整合spring的測試//立馬開啓了spring的註解
@ContextConfiguration(locations="classpath:spring/applicationContext-*.xml")//加載核心配置文件,自動構建spring容器
public class UserMapperSpringTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testQueryUserByTableName() {
        List<User> userList = this.userMapper.queryUserByTableName("tb_user");
        for (User user : userList) {
            System.out.println(user);
        }
    }

    @Test
    public void testLogin() {
        System.out.println(this.userMapper.login("hj", "123456"));
    }

    @Test
    public void testQueryUserById() {
        System.out.println(this.userMapper.queryUserById("1"));
        User user = new User();
        user.setName("美女");
        user.setId("1");
        userMapper.updateUser(user);

        System.out.println(this.userMapper.queryUserById("1"));
    }

    @Test
    public void testQueryUserAll() {
        List<User> userList = this.userMapper.queryUserAll();
        for (User user : userList) {
            System.out.println(user);
        }
    }

    @Test
    public void testInsertUser() {
        User user = new User();
        user.setAge(20);
        user.setBirthday(new Date());
        user.setName("大神");
        user.setPassword("123456");
        user.setSex(2);
        user.setUserName("bigGod222");
        this.userMapper.insertUser(user);
        System.out.println(user.getId());
    }

    @Test
    public void testUpdateUser() {
        User user = new User();
        user.setBirthday(new Date());
        user.setName("靜靜");
        user.setPassword("123456");
        user.setSex(0);
        user.setUserName("Jinjin");
        user.setId("1");
        this.userMapper.updateUser(user);
    }

    @Test
    public void testDeleteUserById() {
        this.userMapper.deleteUserById("1");
    }

    @Test
    public void testqueryUserList() {
        List<User> users = this.userMapper.queryUserList(null);
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    public void queryUserListByNameAndAge() throws Exception {
        List<User> users = this.userMapper.queryUserListByNameAndAge("鵬程", 20);
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    public void queryUserListByNameOrAge() throws Exception {
        List<User> users = this.userMapper.queryUserListByNameOrAge(null, 16);
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    public void queryUserListByIds() throws Exception {
        List<User> users = this.userMapper.queryUserListByIds(new String[]{"5", "2"});
        for (User user : users) {
            System.out.println(user);
        }
    }

目錄結構:

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213559514-141765959.png" data-action="zoom"/> </div>

16.SpringBoot 集成Mybatis

請參見博文:https://blog.csdn.net/hellozpc/article/details/82531834

17.Mybatis Generator的使用

MyBatis Generator(MBG)是MyBatis 和iBATIS的代碼生成器。能夠生成簡單CRUD操做的XML配置文件、Mapper文件(DAO接口)、實體類。實際開發中可以有效減小程序員的工做量,甚至不用程序員手動寫sql。 mybatis-generator有多種用法:命令行、maven插件等。命令行方式一般要把相關jar包下載到本地,再使用java -jar 運行。方便起見,本文演示使用maven插件的方式。

1.新建一個Maven項目(能夠直接創建一個初始的springboot項目)

pom文件引入mybatis-generator-maven-plugin

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213654206-1251964502.png" data-action="zoom"/> </div> ``` <!-- mybatis-generator自動生成代碼插件 --> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.5</version> </plugin> ```

2.將插件須要的配置文件拷入到resource目錄下,並作配置

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213714936-1131791205.png" data-action="zoom"/> </div>

generator.properties:配置數據庫信息,在generatorConfig.xml使用:

#generatorConfig Info
generator.location=D:\\software\\maven\\apache-maven-3.3.9\\repository\\mysql\\mysql-connector-java\\5.1.32\\mysql-connector-java-5.1.32.jar
generator.targetPackage=com.zpc.videoshow.generated
#gererator.schema=oracle-schema
gererator.tableName=video_info
gererator.domainObjectName=VideoInfo

jdbc.driver=com.mysql.jdbc.Driver
jdbc.host=jdbc:mysql://localhost:3306/videoshow
jdbc.userName=root
jdbc.passWord=123456
jdbc.initialSize=0
jdbc.maxActive=20
jdbc.maxIdle=20
jdbc.minIdle=1
jdbc.maxWait=1000

generatorConfig.xml:配置generator插件運行須要的參數信息

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!-- 引入配置文件 -->
    <properties resource="generator.properties"/>
    <!-- 數據庫驅動包位置,路徑請不要有中文-->
    <!-- <classPathEntry location="D:\software\lib\mysql-connector-java-5.1.21.jar" /> -->
    <classPathEntry location="${generator.location}"/>
    <!-- 一個數據庫一個context-->
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <!-- 生成的pojo,將implements Serializable -->
        <plugin type="org.mybatis.generator.plugins.SerializablePlugin"></plugin>

        <!-- 註釋 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true"/><!-- 是否取消註釋 -->
            <!-- <property name="suppressDate" value="true" />  是否生成註釋代時間戳 -->
        </commentGenerator>

        <!-- 數據庫連接URL、用戶名、密碼 -->
        <!-- <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/sy" userId="sypro" password="sypro"> -->
        <jdbcConnection driverClass="${jdbc.driver}" connectionURL="${jdbc.host}" userId="${jdbc.userName}"
                        password="${jdbc.passWord}">
        </jdbcConnection>

        <!-- 類型轉換 -->
        <javaTypeResolver>
            <!-- 默認false,把JDBC DECIMAL 和 NUMERIC 類型解析爲 Integer true,把JDBC DECIMAL
                和 NUMERIC 類型解析爲java.math.BigDecimal -->
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>

        <!-- 生成model模型,設置對應的包名(targetPackage)和存放路徑(targetProject)。targetProject能夠指定具體的路徑,如./src/main/java,也可使用MAVEN來自動生成,這樣生成的代碼會在target/generatord-source目錄下 -->
        <javaModelGenerator targetPackage="${generator.targetPackage}" targetProject="./src/main/java">
            <!-- 是否在當前路徑下新加一層schema,eg:false路徑com.oop.eksp.user.model 而true:com.oop.eksp.user.model.[schemaName] -->
            <property name="enableSubPackages" value="false"/>
            <!-- 從數據庫返回的值被清理先後的空格 -->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <!--對應的mapper.xml文件 -->
        <sqlMapGenerator targetPackage="${generator.targetPackage}" targetProject="./src/main/java">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>

        <!-- 對應的Mapper接口類文件 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="${generator.targetPackage}"
                             targetProject="./src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>

        <!-- 列出要生成代碼的全部表,這裏配置的是不生成Example文件 -->
        <!-- schema即爲數據庫名tableName爲對應的數據庫表 domainObjectName是要生成的實體類 enable*ByExample是否生成 example類   -->
        <table tableName="${gererator.tableName}" domainObjectName="${gererator.domainObjectName}"
               schema="${gererator.schema}"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
            <!-- 忽略列,不生成bean 字段
            <ignoreColumn column="FRED" />-->
            <!-- 指定列的java數據類型
            <columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" />  -->
            <!-- 用於指定生成實體類時是否使用實際的列名做爲實體類的屬性名。false是 Camel Case風格-->
            <property name="useActualColumnNames" value="false"/>
        </table>
    </context>
</generatorConfiguration>

3.運行generator插件(確保數據庫已經運行)

  • 方法1:直接找到mybatis-generator的插件,右擊運行。

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213757424-860588927.png" data-action="zoom"/> </div>

  • 方法2:在運行配置裏面添加maven命令

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213802501-258012318.png" data-action="zoom"/> </div> <div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213807389-968509349.png" data-action="zoom"/> </div>

4.查看生成的文件

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327213817613-1594954082.png" data-action="zoom"/> </div>

5.一些小技巧

  • a) 建表時,字段名稱建議用"_"分隔多個單詞,好比:AWB_NO、REC_ID…,這樣生成的entity,屬性名稱就會變成漂亮的駝峯命名,即:awbNo、recId

  • b)oracle中,數值形的字段,若是指定精度,好比Number(16,2),默認生成entity屬性是BigDecimal型 ,若是不指定精度,好比:Number(8),指默認生成的是Long型

  • c)oracle中的nvarchar/nvarchar2,mybatis-generator會識別成Object型,建議不要用nvarchar2,改用varchar2

6.Example文件的使用

用過Hibernate的同窗必定感嘆於其徹底不用手動寫sql的強大功能,其實Mybatis也能夠配置生成Example,省去一些簡單的sql編寫,實際開發中也會帶來方便。

  • a.修改generatorConfig.xml的配置:
enableCountByExample="true" enableUpdateByExample="true"
 enableDeleteByExample="true" enableSelectByExample="true"
 selectByExampleQueryId="true"
  • b.pom中引入mybatis的依賴:
<dependency>
   <groupId>org.mybatis</groupId>
   <artifactId>mybatis</artifactId>
   <version>3.4.1</version>
</dependency>
  • c.運行generator

這種狀況下多生成了一個Example的文件,Mapper文件的內容也會多不少example相關的:

<div align=center> <img src="https://img2018.cnblogs.com/blog/1456626/201903/1456626-20190327214003026-363927217.png" data-action="zoom"/> </div>

Example的詳細使用百度之,參見: https://blog.csdn.net/m0_37795198/article/details/78848045

18.MyBatis整合分頁插件 pageHelper

請參見博文:https://blog.csdn.net/hellozpc/article/details/82531834

相關文章
相關標籤/搜索