Mybatis快速入門——Mybatis學習總結(一)
一.Mybatis介紹
MyBatis 本是apache的一個開源專案iBatis, 2013年11月遷移到Github。
MyBatis是一個優秀的持久層框架,它對jdbc的操作資料庫的過程進行封裝,使開發者只需要關注 SQL 本身。
Mybatis通過xml或註解的方式將要執行的各種statement(statement、preparedStatemnt、CallableStatement)配置起來,並通過java物件和statement中的sql進行對映生成最終執行的sql語句,最後由mybatis框架執行sql並將結果對映成java物件並返回。
二. Mybatis框架圖
三. 入門專案實踐
3.1 環境搭建
依照上述方法加入 junit單元測試包, mysql 或者 oracle 連線啟動包 ,就可以了 。
3.2 加入配置檔案
3.2.1 log4j.properties log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.err log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n ### direct messages to file mylog.log ### log4j.appender.file=org.apache.log4j.FileAppender log4j.appender.file.File=G:/Log4j_log/MyBatis_Base_log log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n ### set log levels - for more verbose logging change 'info' to 'debug' ### log4j.rootLogger=debug, stdout
3.2.2 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_base?characterEncoding=utf-8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/tzq/batis/slqmap/User.xml"/> </mappers> </configuration>
3.3 建立pojo
pojo類作為mybatis進行sql對映使用,po類通常與資料庫表對應。
資料庫表
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;
User.java
package com.tzq.batis.pojo;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer id;
private String username;// 使用者姓名
private String sex;// 性別
private Date birthday;// 生日
private String address;// 地址
public Integer getId() {
return id;
}
public void setId(Integer 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 + "]";
}
}
3.4 建立sql 對映檔案
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:名稱空間,用於隔離sql,已經當 id 有重新命名時 ,區分的標識 -->
<mapper namespace="test">
</mapper>
3.5 實現根據id查詢使用者
在user.xml中新增select標籤,編寫sql:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:名稱空間,用於隔離sql,已經當 id 有重新命名時 ,區分的標識 -->
<mapper namespace="test">
<!-- id:statement的id 或者叫做sql的id-->
<!-- parameterType:宣告輸入引數的型別 -->
<!-- resultType:宣告輸出結果的型別,應該填寫pojo的全路徑 -->
<!-- #{}:輸入引數的佔位符,相當於jdbc的? -->
<select id="queryUserById" parameterType="int"
resultType="cn.itcast.mybatis.pojo.User">
SELECT * FROM `user` WHERE id = #{id}
</select>
</mapper>
3.6 測試程式:
public class MybatisTest {
private SqlSessionFactory sqlSessionFactory = null;
@Before
public void init() throws Exception {
// 1. 建立SqlSessionFactoryBuilder物件
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2. 載入SqlMapConfig.xml配置檔案
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 3. 建立SqlSessionFactory物件
this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
}
@Test
public void testQueryUserById() throws Exception {
// 4. 建立SqlSession物件
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 執行SqlSession物件執行查詢,獲取結果User
// 第一個引數是User.xml的statement的id,第二個引數是執行sql需要的引數;
Object user = sqlSession.selectOne("queryUserById", 1);
// 6. 列印結果
System.out.println(user);
// 7. 釋放資源
sqlSession.close();
}
}
執行結果
更多sql 操作的 user.xml 程式碼
<!-- 寫sql語句 , namespace 表示當id 在 另一個 xml map檔案中有一樣的名字是 , 可以通過它來判斷是哪一個-->
<mapper namespace="com.tzq.batis.mapperdao.UserMapperDao">
<!-- #{}是 mybatis 裡的萬用字元 resultType 代表 執行後的結果型別 parameterType 代表 下面萬用字元的屬性型別-->
<!-- 通過ID查詢-->
<select id="findByid" resultType="com.tzq.batis.pojo.User" parameterType="Integer">
select * from user where id = #{VALUE }
</select>
<!-- 根據使用者名稱模糊查詢資料
#{} 表示佔位符 #{} == ? 轉換為 sql 會 給 #{} 的外出加上 '' 單引號
${} 表示 字串拼接 拼接不會加單引號
-->
<select id="findUserByName" resultType="com.tzq.batis.pojo.User" parameterType="String">
<!-- select * from user where username like "%"#{可以隨便起名}"%" 與 下面語句一樣的效果 -->
select * from user where username like '%${value}%'
</select>
<!-- 新增使用者-->
<insert id="insertUser" parameterType="com.tzq.batis.pojo.User">
<selectKey resultType="integer" keyProperty="id" order="AFTER">
select LAST_INSERT_ID()
</selectKey>
insert into user
(username , sex) values (#{username},#{sex})
</insert>
<!-- 更新使用者-->
<update id="updateUser" parameterType="com.tzq.batis.pojo.User">
update user SET username = #{username} where id = #{id}
</update>
<!-- 刪除使用者 -->
<delete id="deleteUser" parameterType="com.tzq.batis.pojo.User">
delete FROM user where id = #{id}
</delete>
</mapper>
對應的java程式碼
public class TestUserMybatis {
/*
獲取session
*/
public SqlSession getSqlSession() throws IOException {
//載入核心配置檔案
String resource = "sqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//建立SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//建立sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}
/*
通過了ID 查詢資料
*/
@Test
public void testSelect() throws IOException {
SqlSession sqlSession = getSqlSession();
//執行sql語句 ,表示查詢一個
User user = sqlSession.selectOne("com.tzq.batis.mapperdao.UserMapperDao.findByid", 1);
System.out.println(user.toString());
sqlSession.close();
}
/*
根據使用者名稱模糊查詢資料
*/
@Test
public void testFindDimName() throws IOException {
SqlSession sqlSession = getSqlSession();
//執行sql語句
List<User> list = sqlSession.selectList("test.findUserByName", "五");
for (User user : list) {
System.out.println(user.toString());
}
sqlSession.close();
}
/*
新增使用者
*/
@Test
public void testInsertUser() throws IOException {
SqlSession sqlSession = getSqlSession();
//執行sql語句
User user = new User();
user.setUsername("李四");
user.setSex("男");
int insert = sqlSession.insert("test.insertUser", user);
sqlSession.commit();
sqlSession.close();
System.out.println(user.getId());
}
/*
修改使用者
*/
@Test
public void testUpdateUserById() throws IOException {
SqlSession sqlSession = getSqlSession();
//執行sql語句
User user = new User();
user.setId(29);
user.setUsername("張三");
sqlSession.update("updateUser", user);
sqlSession.commit();
sqlSession.close();
}
/*
刪除使用者
*/
@Test
public void testDeleteUserById() throws IOException {
SqlSession sqlSession = getSqlSession();
//執行sql語句
User user = new User();
user.setId(29);
sqlSession.update("deleteUser", user);
sqlSession.commit();
sqlSession.close();
}
}
3.7 小結
3.7.1 #{}和${}
#{}表示一個佔位符號,通過#{}可以實現preparedStatement向佔位符中設定值,自動進行java型別和jdbc型別轉換。#{}可以有效防止sql注入。 #{}可以接收簡單型別值或pojo屬性值。 如果parameterType傳輸單個簡單型別值,#{}括號中可以是value或其它名稱。
3.7.2. parameterType和resultType
parameterType:指定輸入引數型別,mybatis通過ognl從輸入物件中獲取引數值拼接在sql中。
resultType:指定輸出結果型別,mybatis將sql查詢結果的一行記錄資料對映為resultType指定型別的物件。如果有多條資料,則分別進行對映,並把物件放到容器List中
3.7.3. selectOne和selectList
selectOne查詢一條記錄,如果使用selectOne查詢多條記錄則丟擲異常:
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70)
selectList可以查詢一條或多條記錄。
3.8 Dao開發
3.8.1傳統Dao的開發
Dao介面
public interface UserDao {
public User selectUserById(Integer id);
}
Dao介面的實現類
public class UserDaoImpl implements UserDao {
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public User selectUserById(Integer id) {
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("findByid", id);
return user;
}
}
junit 測試類
public class TestUserDao {
private SqlSessionFactory sqlSessionFactory;
@Before
public void before() throws Exception {
//載入核心配置檔案
String resource = "sqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//建立SqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
/**
* Method: TestDao()
*/
@Test
public void testTestDao() throws Exception {
UserDao dao = new UserDaoImpl(sqlSessionFactory);
User user = dao.selectUserById(10);
System.out.println(user.getUsername());
}
}
3.9 重量級嘉賓登場 —— Mapper動態代理方式
3.9.1 開發規範
Mapper介面開發方法只需要程式設計師編寫Mapper介面(相當於Dao介面),由Mybatis框架根據介面定義建立介面的動態代理物件,代理物件的方法體同上邊Dao介面實現類方法。
#代理的介面程式碼:
public interface UserMapperDao {
/**
* Mapper 動態代理方法
* 只要實現了下面的四個原則 , 就不用寫daoImpl 了
* Created by MyPC on 2017/8/19.
*/
/*
四個原則
1.介面的方法名與 Mapper.xml 中的 id 名 一樣
2.返回值型別與Mapper.xml檔案中返回值型別一致
3.方法的 輸入引數 型別要與 Mapper.xml 的一致
4.Mapper.xml名稱空間繫結這個介面全路徑名
*/
public User findByid(Integer id);
}
#junit測試類
public class TestUserMapperDao {
@Test
public void testSelectUserById() throws IOException {
//載入核心配置檔案
String resource = "sqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//建立SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//建立sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapperDao dao = sqlSession.getMapper(UserMapperDao.class);
User user = dao.findByid(10);
System.out.println(user.toString());
}
}
官網推薦使用 動態代理的方式 , 當然您可以根據自己的需求去寫。