1.從JDBC談起
1.1.使用IDEA創建maven工程



1.2.引入mysql依賴包
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>

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缺點分析

2.MyBatis介紹

官方文檔 http://www.mybatis.org/mybatis-3/getting-started.html
3.Mybaits整體架構


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&characterEncoding=utf-8&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
<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.目錄結構

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 全局的配置文件 (1、數據源,2、外部的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


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.目錄結構

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中的問題
- 1、接口->實現類->mapper.xml
- 2、實現類中,使用mybatis的方式非常類似
- 3、xml中的sql statement 硬編碼到java代碼中。
思考:能否只寫接口,不寫實現類。只編寫接口和Mapper.xml即可?
因為在dao(mapper)的實現類中對sqlsession的使用方式很類似。因此mybatis提供了接口的動態代理。
7.2.使用動態代理改造CRUD
- 修改測試用例的setUp方法

- 執行queryUserAll()方法

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.完整的例子
1、創建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);
}
2、創建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>
3、全局配置文件mybatis-config.xml引入UserMapper.xml
<mappers>
<mapper resource="mappers/MyMapper.xml"/>
<mapper resource="mappers/UserDaoMapper.xml"/>
<mapper resource="mappers/UserMapper.xml"/>
</mappers>
4、創建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");
}
}
目錄結構:

7.4.動態代理總結

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

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

<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 類型內建了許多相應的類型別名。它們都是大小寫不敏感的.

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執行效率,也可以使用插件機制
原理:

自定義攔截器:
// 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
- 1、定義一個接口。
- 2、在接口所在的包中定義mapper.xml,並且要求xml文件和interface的名稱要相同。
- 3、在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>
問題:
- 1、mapper.xml 和 java文件沒有分離。 之后的教程講述和spring整合之后解決。
- 2、需要一個一個的去加載mapper。
當然也可以使用包掃描(必須使用注解方式,即在接口方法上使用注解,如@Select("select * from tb_user ")):
缺點:
- 1、如果包的路徑有很多?
- 2、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);
測試輸出:

有問題,報語法錯誤:相當於執行了這樣一條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


使用:

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
場景:查詢男性用戶,如果輸入了姓名,按姓名模糊查詢

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.一級緩存

在mybatis中,一級緩存默認是開啟的,並且一直無法關閉
一級緩存滿足條件:
- 1、同一個session中
- 2、相同的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 中去關閉二級緩存

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

12.高級查詢
12.1.表關系說明

創建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;
}
需求說明:

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());
}
至此,目錄結構如下:

數據庫腳本:
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的繼承

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.延遲加載


編寫接口:

Mapper配置:

測試:

結果:

開啟延遲加載:

修改測試用例:

執行,報錯:

添加cglib:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
執行:

14.如果sql語句中出現’<’的解決方案
1、使用xml中的字符實體

因為業務,需要在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 <= CURRENT_DATE AND end_date >= CURRENT_DATE
案例:
1.<if test="startDateTime!=null"> and mm.ttime > to_date(#{startDateTime},'yyyy-mm-dd hh24:mi:ss')</if>
2.<if test="endDateTime!=null"> and mm.ttime <= to_date(#{endDateTime},'yyyy-mm-dd hh24:mi:ss')</if>
2、使用<![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)
注意:
使用 標記的sql語句中的
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&characterEncoding=utf-8&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);
}
}
目錄結構:

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

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

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的插件,右擊運行。

- 方法2:在運行配置里面添加maven命令


4.查看生成的文件

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相關的:

Example的詳細使用百度之,參見:
https://blog.csdn.net/m0_37795198/article/details/78848045
18.MyBatis整合分頁插件 pageHelper
請參見博文:https://blog.csdn.net/hellozpc/article/details/82531834