1. Mybatis官網
下載地址
解壓之后的內容:

Mybatis框架結構:

簡要概述:
- SqlMapConfig.xml,此文件作為mybatis的全局配置文件,配置了mybatis的運行環(huán)境等信息。mapper.xml文件即sql映射文件,文件中配置了操作數(shù)據庫的sql語句,此文件需要在SqlMapConfig.xml中加載。
- 通過mybatis環(huán)境等配置信息構造SqlSessionFactory(即會話工廠)。
- 由會話工廠創(chuàng)建sqlSession即會話,操作數(shù)據庫需要通過sqlSession進行。
- mybatis底層自定義了Executor執(zhí)行器接口操作數(shù)據庫,Executor接口有兩個實現(xiàn),一個是基本執(zhí)行器、一個是緩存執(zhí)行器。
- MappedStatement也是mybatis一個底層封裝對象,它包裝了mybatis配置信息及sql映射信息等。mapper.xml文件中一個sql對應一個MappedStatement對象,sql的id即是MappedStatement的id。
- MappedStatement對sql執(zhí)行輸入參數(shù)進行定義,包括HashMap、基本類型、pojo,Executor通過MappedStatement在執(zhí)行sql前將輸入的java對象映射至sql中,輸入參數(shù)映射就是JDBC編程中對preparedStatement設置參數(shù)。
- MappedStatement對sql執(zhí)行輸出結果進行定義,包括HashMap、基本類型、pojo,Executor通過MappedStatement在執(zhí)行sql后將輸出結果映射至java對象中,輸出結果映射過程相當于JDBC編程中對結果的解析處理過程。
2. 導入數(shù)據庫表
1). 使用Navicat工具,在root上右鍵選擇新建數(shù)據庫

2). 新建數(shù)據庫->確定

3). 打開數(shù)據庫mybatis->在mybatis/表處單擊右鍵選擇運行SQL文件...

4). 選擇桌面的sql文件->點擊開始

mybatis.sql文件內容
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `orders`
-- ----------------------------
DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '下單用戶id',
`number` varchar(32) NOT NULL COMMENT '訂單號',
`createtime` datetime NOT NULL COMMENT '創(chuàng)建訂單時間',
`note` varchar(100) DEFAULT NULL COMMENT '備注',
PRIMARY KEY (`id`),
KEY `FK_orders_1` (`user_id`),
CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of orders
-- ----------------------------
INSERT INTO `orders` VALUES ('3', '1', '1000010', '2015-02-04 13:22:35', null);
INSERT INTO `orders` VALUES ('4', '1', '1000011', '2015-02-03 13:22:41', null);
INSERT INTO `orders` VALUES ('5', '10', '1000012', '2015-02-12 16:13:23', null);
-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用戶名稱',
`birthday` date DEFAULT NULL COMMENT '生日',
`sex` char(1) DEFAULT NULL COMMENT '性別',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', '王五', null, '2', null);
INSERT INTO `user` VALUES ('10', '張三', '2014-07-10', '1', '北京市');
INSERT INTO `user` VALUES ('16', '張小明', null, '1', '河南鄭州');
INSERT INTO `user` VALUES ('22', '陳小明', null, '1', '河南鄭州');
INSERT INTO `user` VALUES ('24', '張三豐', null, '1', '河南鄭州');
INSERT INTO `user` VALUES ('25', '陳小明', null, '1', '河南鄭州');
INSERT INTO `user` VALUES ('26', '王五', null, null, null);
5). 導入成功后,刷新表,數(shù)據如下:

3. 測試
1). 創(chuàng)建新的Java工程,并導入Mybatis使用的java包,注意要導入對應的數(shù)據庫驅動包(這里導入的是mysql-connector-java-5.1.42-bin.jar)

2). 在工程目錄下創(chuàng)建一個源碼包config,并在config包下創(chuàng)建sqlmap包、log4j.properties和SqlMapConfig.xml文件。

log4j.properties文件內容
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
SqlMapConfig.xml文件內容
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 和spring整合后environments配置將廢除 -->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事務管理 -->
<transactionManager type="JDBC" />
<!-- 數(shù)據庫連接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
</configuration>
SqlMapConfig.xml是mybatis的核心配置文件,以上文件的配置內容為數(shù)據源、事務管理。
注意:等后面mybatis和Spring兩個框架整合之后,environments的配置將被廢除.
3). 創(chuàng)建一個po類--User
po類作為mybatis進行sql映射使用,po類通常與數(shù)據庫表對應,User.java文件的內容如下:
public class User {
// id
private int id;
// 用戶名
private String username;
// 性別
private String sex;
// 用戶名
private Date birthday;
// 地址
private String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address="
+ address + "]";
}
}
4). 在classpath下的sqlmap目錄下創(chuàng)建sql映射文件user.xml
user.xml內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test">
</mapper>
- namespace:即命名空間,其用于隔離sql語句(即不同sql映射文件中的兩個相同id的sql語句如何來區(qū)分)
5). 加載映射文件
mybatis框架需要加載映射文件,將user.xml添加在SqlMapConfig.xml中.
在SqlMapConfig.xml配置文件中添加配置信息:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 和spring整合后environments配置將廢除 -->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事務管理 -->
<transactionManager type="JDBC" />
<!-- 數(shù)據庫連接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<!-- 添加的內容 -->
<mappers>
<!-- resource是基于classpath來查找的 -->
<mapper resource="sqlmap/user.xml"/>
</mappers>
</configuration>
6). 入門程序測試——根據id查詢用戶信息
I. user.xml映射文件中添加如下配置:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test">
<!-- 根據id獲取用戶信息,
parameterType: 查詢參數(shù)的數(shù)據類型,即定義輸入到sql中的映射類型
resultType: 查詢結果的數(shù)據類型,如果是pojo則該給出全路徑
#{id}表示使用PreparedStatement設置占位符號并將輸入變量id傳到sql中,#{}作用就是占位符,相當于JDBC中的?
-->
<select id="getUserById" parameterType="int" resultType="com.mazaiting.po.User">
select * from user where id = #{id};
</select>
</mapper>
II. 編寫MybatisTest類
public class MybatisTest {
@Test
public void testGetUserById() throws IOException {
// 1. 創(chuàng)建SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 創(chuàng)建SqlSessionFactory對象
SqlSessionFactory factory = builder.build(inputStream);
// 4. 創(chuàng)建SqlSession對象
SqlSession sqlSession = factory.openSession();
// 5. 使用SqlSession對象執(zhí)行查詢,得到User對象
// 第一個參數(shù): 執(zhí)行查詢的StatementId,即配置文件user.xml中的id, 第二參數(shù)傳入id對應的值
User user = sqlSession.selectOne("getUserById", 10);
// 6. 打印結果
System.out.println(user);
// 7. 釋放資源
sqlSession.close();
}
}
III. 執(zhí)行測試代碼, 打印結果:

IV. 優(yōu)化代碼
一般來講工廠對象一般在實際開發(fā)是單例的,并不需要頻繁地創(chuàng)建
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 創(chuàng)建SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 創(chuàng)建SqlSessionFactory對象
factory = builder.build(inputStream);
}
@Test
public void testGetUserById() {
// 4. 創(chuàng)建SqlSession對象
SqlSession sqlSession = factory.openSession();
// 5. 使用SqlSession對象執(zhí)行查詢,得到User對象
// 第一個參數(shù): 執(zhí)行查詢的StatementId,即配置文件user.xml中的id, 第二參數(shù)傳入id對應的值
User user = sqlSession.selectOne("getUserById", 10);
// 6. 打印結果
System.out.println(user);
// 7. 釋放資源
sqlSession.close();
}
}
7). 根據用戶名稱模糊查詢用戶信息列表
I. user.xml文件添加
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test">
<!-- 如果查詢結果返回的是List集合,那么resultType只需要設置為List集合中的一個元素的數(shù)據類型 -->
<select id="getUserByName" parameterType="string" resultType="com.mazaiting.po.User">
select * from user where username like #{username}
</select>
</mapper>
II. 編寫測試方法
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 創(chuàng)建SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 創(chuàng)建SqlSessionFactory對象
factory = builder.build(inputStream);
}
@Test
public void testGetUserByName() {
SqlSession session = factory.openSession();
List<User> list = session.selectList("getUserByName", "%張%");
for (User user : list) {
System.out.println(user.toString());
}
session.close();
}
}
III. 執(zhí)行測試方法,打印結果:

IV. 另一個中不建議使用的占位符方式
<?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="test">
<!-- 如果查詢結果返回的是List集合,那么resultType只需要設置為List集合中的一個元素的數(shù)據類型 -->
<select id="getUserByName1" parameterType="string" resultType="com.mazaiting.po.User">
select * from user where username like '%${value}%'
</select>
</mapper>
測試代碼:
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 創(chuàng)建SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 創(chuàng)建SqlSessionFactory對象
factory = builder.build(inputStream);
}
@Test
public void testGetUserByName1() {
SqlSession session = factory.openSession();
List<User> list = session.selectList("getUserByName1", "張");
for (User user : list) {
System.out.println(user.toString());
}
session.close();
}
}

不推薦使用:原因容易引起SQL注入。
總結
---{}和${}
1). #{}:表示一個占位符號,可以很好地去避免sql注入。其原理是將占位符位置的整個參數(shù)和sql語句兩部分提交給數(shù)據庫,數(shù)據庫去執(zhí)行sql語句,去表中匹配所有的記錄是否和整個參數(shù)是否一致。
#{}要獲取輸入參數(shù)的值:
- 如果輸入參數(shù)是簡單數(shù)據類型,則
#{}中可以寫value或其它名稱。 - 如果輸入參數(shù)是pojo對象類型,則
#{}可通過OGNL方式去獲取,表達式就是屬性.屬性.屬性....方式。
2). ${}表示一個sql拼接符號,其原理是在向數(shù)據庫發(fā)出sql之前去拼接好sql再提交給數(shù)據庫執(zhí)行。
${}要獲取輸入參數(shù)的值:
- 如果輸入參數(shù)是簡單數(shù)據類型,則
${}中只能寫value。 - 如果輸入參數(shù)是pojo對象類型,則
${}可通過OGNL方式去獲取,表達式就是屬性.屬性.屬性....方式。
一般情況下建議使用#{},特殊情況下必須要用${},比如:
1>. 動態(tài)拼接sql中動態(tài)組成排序字段,要通過${}將排序字段傳入sql中。
2>. 動態(tài)拼接sql中動態(tài)組成表名,要通過${}將表名傳入sql中。
---parameterType和resultType
- parameterType:指定輸入參數(shù)類型,mybatis通過ognl從輸入對象中獲取參數(shù)值拼接在sql中。
- resultType:指定輸出結果類型,mybatis將sql查詢結果的一行記錄數(shù)據映射為resultType指定類型的對象。
---selectOne()和selectList()方法
- selectOne查詢一條記錄,如果使用selectOne查詢多條記錄則拋出異常.
- selectList可以查詢一條或多條記錄。
4. 其他操作
1). 插入數(shù)據
I. user.xml添加配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test">
<!-- 插入數(shù)據 -->
<insert id="addUser" parameterType="com.mazaiting.po.User">
insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
</mapper>
如果輸入參數(shù)是pojo,那么#{}中的名稱就是pojo類中的屬性(用到了對象圖導航的思想)
II. 編寫測試代碼
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 創(chuàng)建SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 創(chuàng)建SqlSessionFactory對象
factory = builder.build(inputStream);
}
@Test
public void testAddUser() {
// 創(chuàng)建Session對象
SqlSession session = factory.openSession();
// 創(chuàng)建對象
User user = new User();
user.setUsername("mazaiting");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("科學院");
// 插入數(shù)據
session.insert("addUser", user);
// 關閉Session
session.close();
}
}
III. 執(zhí)行測試代碼,打印結果:
可以看出雖然執(zhí)行了sql語句,但是事務并沒有提交,而是回滾了。

IV. 因此,應將測試代碼修改為
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 創(chuàng)建SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 創(chuàng)建SqlSessionFactory對象
factory = builder.build(inputStream);
}
@Test
public void testAddUser() {
// 創(chuàng)建Session對象
SqlSession session = factory.openSession();
// 創(chuàng)建對象
User user = new User();
user.setUsername("mazaiting");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("科學院");
// 插入數(shù)據
session.insert("addUser", user);
// 提交事務
session.commit();
// 關閉Session
session.close();
}
}
V. 執(zhí)行單元測試,打印結果:

2). 自增主鍵返回
- LAST_INSERT_ID():返回auto_increment自增列新記錄id值。該函數(shù)是在當前事務下取到你最后生成的id值,而我們應知道查詢操作是沒有開啟事務的,增刪改操作是需要開啟事務的。
I. 在user.xml中添加配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test">
<!-- 插入數(shù)據,返回主鍵 -->
<insert id="addUser" parameterType="com.mazaiting.po.User">
<selectKey keyProperty="id" resultType="int" order="AFTER">
select LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
</mapper>
- keyProperty:返回的主鍵存儲在pojo中的哪個屬性(即其對應pojo的主鍵屬性)。獲取主鍵,實際上是將主鍵取出來之后封裝到了pojo的主鍵屬性當中。
- resultType:返回的主鍵是什么類型(即其對應pojo的主鍵的數(shù)據類型)。
- order:selectKey的執(zhí)行順序,是相對于insert語句來說的,由于mysql的自增原理,執(zhí)行完insert語句之后才將主鍵生成,所以這里selectKey的執(zhí)行順序為AFTER。
II. 添加測試代碼
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 創(chuàng)建SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 創(chuàng)建SqlSessionFactory對象
factory = builder.build(inputStream);
}
@Test
public void testAddUser1() {
// 創(chuàng)建Session對象
SqlSession session = factory.openSession();
// 創(chuàng)建對象
User user = new User();
user.setUsername("mazaiting");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("科學院");
// 插入數(shù)據
session.insert("addUser1", user);
System.out.println("插入的id:" + user.getId());
// 提交事務
session.commit();
// 關閉Session
session.close();
}
}
III. 執(zhí)行測試代碼,打印結果:

3). 刪除用戶
I. user.xml中添加刪除語句
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test">
<!-- 刪除數(shù)據 -->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
</mapper>
II. 測試代碼
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 創(chuàng)建SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 創(chuàng)建SqlSessionFactory對象
factory = builder.build(inputStream);
}
@Test
public void testDeleteUser() {
// 創(chuàng)建會話
SqlSession session = factory.openSession();
// 刪除數(shù)據
session.delete("deleteUser", 29);
// 提交事務
session.commit();
// 關閉會話
session.close();
}
}
III. 打印結果:

4). 更新數(shù)據
I. user.xml添加配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test">
<!-- 修改用戶信息 -->
<update id="updateUser" parameterType="com.mazaiting.po.User">
update user set username = #{username} where id = #{id}
</update>
</mapper>
II. 測試代碼
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 創(chuàng)建SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 創(chuàng)建SqlSessionFactory對象
factory = builder.build(inputStream);
}
public void testUpdateUser(){
// 創(chuàng)建會話
SqlSession session = factory.openSession();
User user = new User();
user.setId(10);
user.setUsername("張某某");
// 更新數(shù)據
session.update("updateUser", user);
// 提交事務
session.commit();
// 關閉會話
session.close();
}
}
III. 打印結果:

5. Mybatis與Hibernate不同
- MyBatis學習成本低,入門門檻低。MyBatis需要程序員自己寫sql,對sql修改和優(yōu)化就比較靈活。MyBatis是不完全的ORM框架,MyBatis需要程序員編寫sql,但是MyBatis也存在映射(輸入映射、輸出映射)適用場景:需求變化較快的項目開發(fā),比如互聯(lián)網項目、電商。
- Hibernate學習成本高,入門門檻高,Hibernate是ORM框架,不需要程序員編寫sql,自動根據對象映射生成sql。適用場景:需求固定的中小型項目,如OA系統(tǒng)、ERP系統(tǒng)。