1. Mybatis官網
下載下傳位址解壓之後的内容:
圖1.png
Mybatis架構結構:
圖2.png
簡要概述:
- SqlMapConfig.xml,此檔案作為mybatis的全局配置檔案,配置了mybatis的運作環境等資訊。mapper.xml檔案即sql映射檔案,檔案中配置了操作資料庫的sql語句,此檔案需要在SqlMapConfig.xml中加載。
- 通過mybatis環境等配置資訊構造SqlSessionFactory(即會話工廠)。
- 由會話工廠建立sqlSession即會話,操作資料庫需要通過sqlSession進行。
- mybatis底層自定義了Executor執行器接口操作資料庫,Executor接口有兩個實作,一個是基本執行器、一個是緩存執行器。
- MappedStatement也是mybatis一個底層封裝對象,它包裝了mybatis配置資訊及sql映射資訊等。mapper.xml檔案中一個sql對應一個MappedStatement對象,sql的id即是MappedStatement的id。
- MappedStatement對sql執行輸入參數進行定義,包括HashMap、基本類型、pojo,Executor通過MappedStatement在執行sql前将輸入的java對象映射至sql中,輸入參數映射就是JDBC程式設計中對preparedStatement設定參數。
- MappedStatement對sql執行輸出結果進行定義,包括HashMap、基本類型、pojo,Executor通過MappedStatement在執行sql後将輸出結果映射至java對象中,輸出結果映射過程相當于JDBC程式設計中對結果的解析處理過程。
2. 導入資料庫表
1). 使用Navicat工具,在root上右鍵選擇建立資料庫
圖3.png
2). 建立資料庫->确定
圖4.png
3). 打開資料庫mybatis->在mybatis/表處單擊右鍵選擇運作SQL檔案...
圖5.png
4). 選擇桌面的sql檔案->點選開始
圖6.png
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 '建立訂單時間',
`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). 導入成功後,重新整理表,資料如下:
圖7.png
3. 測試
1). 建立新的Java工程,并導入Mybatis使用的java包,注意要導入對應的資料庫驅動包(這裡導入的是mysql-connector-java-5.1.42-bin.jar)
2). 在工程目錄下建立一個源碼包config,并在config包下建立sqlmap包、log4j.properties和SqlMapConfig.xml檔案。
圖8.png
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" />
<!-- 資料庫連接配接池 -->
<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的核心配置檔案,以上檔案的配置内容為資料源、事務管理。
注意:等後面mybatis和Spring兩個架構整合之後,environments的配置将被廢除.
3). 建立一個po類--User
po類作為mybatis進行sql映射使用,po類通常與資料庫表對應,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目錄下建立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語句如何來區分)
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" />
<!-- 資料庫連接配接池 -->
<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: 查詢參數的資料類型,即定義輸入到sql中的映射類型
resultType: 查詢結果的資料類型,如果是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. 建立SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置檔案
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 建立SqlSessionFactory對象
SqlSessionFactory factory = builder.build(inputStream);
// 4. 建立SqlSession對象
SqlSession sqlSession = factory.openSession();
// 5. 使用SqlSession對象執行查詢,得到User對象
// 第一個參數: 執行查詢的StatementId,即配置檔案user.xml中的id, 第二參數傳入id對應的值
User user = sqlSession.selectOne("getUserById", 10);
// 6. 列印結果
System.out.println(user);
// 7. 釋放資源
sqlSession.close();
}
}
III. 執行測試代碼, 列印結果:
圖9.png
IV. 優化代碼
一般來講工廠對象一般在實際開發是單例的,并不需要頻繁地建立
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 建立SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置檔案
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 建立SqlSessionFactory對象
factory = builder.build(inputStream);
}
@Test
public void testGetUserById() {
// 4. 建立SqlSession對象
SqlSession sqlSession = factory.openSession();
// 5. 使用SqlSession對象執行查詢,得到User對象
// 第一個參數: 執行查詢的StatementId,即配置檔案user.xml中的id, 第二參數傳入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集合中的一個元素的資料類型 -->
<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. 建立SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置檔案
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 建立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. 執行測試方法,列印結果:
圖10.png
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集合中的一個元素的資料類型 -->
<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. 建立SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置檔案
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 建立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();
}
}
圖11.png
不推薦使用:原因容易引起SQL注入。
總結
---{}和${}
1).
#{}
:表示一個占位符号,可以很好地去避免sql注入。其原理是将占位符位置的整個參數和sql語句兩部分送出給資料庫,資料庫去執行sql語句,去表中比對所有的記錄是否和整個參數是否一緻。
#{}
要擷取輸入參數的值:
- 如果輸入參數是簡單資料類型,則
中可以寫value或其它名稱。#{}
- 如果輸入參數是pojo對象類型,則
可通過OGNL方式去擷取,表達式就是#{}
方式。屬性.屬性.屬性....
2).
${}
表示一個sql拼接符号,其原理是在向資料庫發出sql之前去拼接好sql再送出給資料庫執行。
${}
-
中隻能寫value。${}
-
${}
屬性.屬性.屬性....
一般情況下建議使用
#{}
,特殊情況下必須要用
${}
,比如:
1>. 動态拼接sql中動态組成排序字段,要通過
${}
将排序字段傳入sql中。
2>. 動态拼接sql中動态組成表名,要通過
${}
将表名傳入sql中。
---parameterType和resultType
- parameterType:指定輸入參數類型,mybatis通過ognl從輸入對象中擷取參數值拼接在sql中。
- resultType:指定輸出結果類型,mybatis将sql查詢結果的一行記錄資料映射為resultType指定類型的對象。
---selectOne()和selectList()方法
- selectOne查詢一條記錄,如果使用selectOne查詢多條記錄則抛出異常.
- selectList可以查詢一條或多條記錄。
4. 其他操作
1). 插入資料
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">
<!-- 插入資料 -->
<insert id="addUser" parameterType="com.mazaiting.po.User">
insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
</mapper>
如果輸入參數是pojo,那麼#{}中的名稱就是pojo類中的屬性(用到了對象圖導航的思想)
II. 編寫測試代碼
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 建立SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置檔案
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 建立SqlSessionFactory對象
factory = builder.build(inputStream);
}
@Test
public void testAddUser() {
// 建立Session對象
SqlSession session = factory.openSession();
// 建立對象
User user = new User();
user.setUsername("mazaiting");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("科學院");
// 插入資料
session.insert("addUser", user);
// 關閉Session
session.close();
}
}
III. 執行測試代碼,列印結果:
可以看出雖然執行了sql語句,但是事務并沒有送出,而是復原了。
圖12.png
IV. 是以,應将測試代碼修改為
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 建立SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置檔案
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 建立SqlSessionFactory對象
factory = builder.build(inputStream);
}
@Test
public void testAddUser() {
// 建立Session對象
SqlSession session = factory.openSession();
// 建立對象
User user = new User();
user.setUsername("mazaiting");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("科學院");
// 插入資料
session.insert("addUser", user);
// 送出事務
session.commit();
// 關閉Session
session.close();
}
}
V. 執行單元測試,列印結果:
圖13.png
2). 自增主鍵傳回
- LAST_INSERT_ID():傳回auto_increment自增列新記錄id值。該函數是在目前事務下取到你最後生成的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">
<!-- 插入資料,傳回主鍵 -->
<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的主鍵的資料類型)。
- order:selectKey的執行順序,是相對于insert語句來說的,由于mysql的自增原理,執行完insert語句之後才将主鍵生成,是以這裡selectKey的執行順序為AFTER。
II. 添加測試代碼
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 建立SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置檔案
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 建立SqlSessionFactory對象
factory = builder.build(inputStream);
}
@Test
public void testAddUser1() {
// 建立Session對象
SqlSession session = factory.openSession();
// 建立對象
User user = new User();
user.setUsername("mazaiting");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("科學院");
// 插入資料
session.insert("addUser1", user);
System.out.println("插入的id:" + user.getId());
// 送出事務
session.commit();
// 關閉Session
session.close();
}
}
III. 執行測試代碼,列印結果:
圖14.png
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">
<!-- 删除資料 -->
<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. 建立SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置檔案
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 建立SqlSessionFactory對象
factory = builder.build(inputStream);
}
@Test
public void testDeleteUser() {
// 建立會話
SqlSession session = factory.openSession();
// 删除資料
session.delete("deleteUser", 29);
// 送出事務
session.commit();
// 關閉會話
session.close();
}
}
III. 列印結果:
圖15.png
4). 更新資料
<?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>
public class MybatisTest {
private SqlSessionFactory factory;
@Before
public void init() throws IOException {
// 1. 建立SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2. 加載配置檔案
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 建立SqlSessionFactory對象
factory = builder.build(inputStream);
}
public void testUpdateUser(){
// 建立會話
SqlSession session = factory.openSession();
User user = new User();
user.setId(10);
user.setUsername("張某某");
// 更新資料
session.update("updateUser", user);
// 送出事務
session.commit();
// 關閉會話
session.close();
}
}
圖16.png
5. Mybatis與Hibernate不同
- MyBatis學習成本低,入門門檻低。MyBatis需要程式員自己寫sql,對sql修改和優化就比較靈活。MyBatis是不完全的ORM架構,MyBatis需要程式員編寫sql,但是MyBatis也存在映射(輸入映射、輸出映射)适用場景:需求變化較快的項目開發,比如網際網路項目、電商。
- Hibernate學習成本高,入門門檻高,Hibernate是ORM架構,不需要程式員編寫sql,自動根據對象映射生成sql。适用場景:需求固定的中小型項目,如OA系統、ERP系統。