Mybatis介紹
MyBatis 本是apache的一個開源項目iBatis, 2010年這個項目由apache software foundation 遷移到了google code诗宣,并且改名為MyBatis 鳞疲。2013年11月遷移到Github寻仗。
MyBatis是一個優(yōu)秀的持久層框架,它對jdbc的操作數(shù)據(jù)庫的過程進行封裝桑阶,使開發(fā)者只需要關注 SQL 本身,而不需要花費精力去處理例如注冊驅動如蚜、創(chuàng)建connection浅碾、創(chuàng)建statement、手動設置參數(shù)从祝、結果集檢索等jdbc繁雜的過程代碼襟己。
Mybatis通過xml或注解的方式將要執(zhí)行的各種statement(statement、preparedStatemnt牍陌、CallableStatement)配置起來擎浴,并通過java對象和statement中的sql進行映射生成最終執(zhí)行的sql語句,最后由mybatis框架執(zhí)行sql并將結果映射成java對象并返回毒涧。
JDBC存在的問題
1贮预、 數(shù)據(jù)庫連接創(chuàng)建、釋放頻繁造成系統(tǒng)資源浪費,從而影響系統(tǒng)性能仿吞。如果使用數(shù)據(jù)庫連接池可解決此問題滑频。
2、 Sql語句在代碼中硬編碼唤冈,造成代碼不易維護峡迷,實際應用中sql變化的可能較大,sql變動需要改變java代碼你虹。
3绘搞、 使用preparedStatement向占有位符號傳參數(shù)存在硬編碼,因為sql語句的where條件不一定傅物,可能多也可能少夯辖,修改sql還要修改代碼,系統(tǒng)不易維護董饰。
4楼雹、 對結果集解析存在硬編碼(查詢列名),sql變化導致解析代碼變化尖阔,系統(tǒng)不易維護贮缅,如果能將數(shù)據(jù)庫記錄封裝成pojo對象解析比較方便。
Mybatis架構
Mybatis使用
mybaits的代碼由github.com管理
下載地址:https://github.com/mybatis/mybatis-3/releases
mybatis如下:
目錄結構
- mybatis-3.2.7.jar mybatis的核心包
- lib文件夾 mybatis的依賴包所在
- mybatis-3.2.7.pdf mybatis使用手冊
創(chuàng)建核心配置文件
<?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ù)據(jù)庫連接池 -->
<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>
- src目錄下創(chuàng)建log4j.properties jdbc.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
- 創(chuàng)建pojo映射文件 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">
<select id="queryUserById" parameterType="Integer" resultType="cn.probuing.mybatisintro.pojo.User">
SELECT *
FROM `user`
WHERE id = #{v}
</select>
</mapper>
標簽解釋
在pojo的映射文件xml中介却,包含<select>谴供、<insert>、<update>齿坷、<delete> 分別對應 查詢桂肌、添加、更新永淌、刪除操作
- 其中 id 代表對應標簽的識別id
- parameterType代表占位符的類型
- resultType 代表返回值類型
語句解釋
#{v}代表占位符 占位符標識為v
${value}代表字符串拼接 標識必須為value
select * from user where username like '%xx%'
- 對應的UserMap.xml配置文件中的SQL文件寫法
SELECT * FROM `user` where username like "%"#{v}"%"
- 測試代碼
@Test
public void testSelectOne() throws IOException {
//創(chuàng)建SqlSessionFactoryBuilder對象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//加載SqlMapConfig.xml配置文件 創(chuàng)建SqlSessionFactory
SqlSessionFactory sessionFactory = builder.build(Resources.getResourceAsStream("SqlMapConfig.xml"));
//創(chuàng)建SqlSession對象
SqlSession sqlSession = sessionFactory.openSession();
//SqlSession執(zhí)行對象查詢
User user = (User) sqlSession.selectOne("queryUserById", 1);
System.out.println(user);
//釋放資源
sqlSession.close();
}
insert
- 映射文件 mapper sql書寫
<insert id="insertUser" parameterType="cn.probuing.mybatisintro.pojo.User">
<!-- 返回最后插入的主鍵id -->
<selectKey keyProperty="id" resultType="Integer" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,address,sex) values(#{username},#{birthday},#{address},#{sex})
</insert>
update
- 映射文件 mapper sql
<!--更新用戶-->
<update id="updateUserById" parameterType="cn.probuing.mybatisintro.pojo.User">
update user
set username=#{username},ses=#{sex},birthday=#{birthday},address=#{address}
where id = #{id}
</update>
- 測試代碼
@Test
public void testUpdateUserById() throws IOException {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory = builder.build(Resources.getResourceAsStream("sqlMapConfig.xml"));
SqlSession sqlSession = sessionFactory.openSession();
User user = new User();
user.setId(33);
user.setUsername("www33333");
user.setSex("釹");
user.setBirthday(new Date());
user.setAddress("332211aasss");
int line = sqlSession.insert("test.updateUserById", user);
sqlSession.commit();
System.out.println(line);
}
delete
- Mapper映射文件
<!--刪除用戶-->
<delete id="deleteUserById" parameterType="Integer">
DELETE from user
WHERE id = #{vvvv}
</delete>
- 測試代碼
@Test
public void testDeleteUserById() throws IOException {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory = builder.build(Resources.getResourceAsStream("sqlMapConfig.xml"));
SqlSession sqlSession = sessionFactory.openSession();
sqlSession.delete("test.deleteUserById", 32);
sqlSession.commit();
}
MyBatis 解決JDBC的需求
1崎场、數(shù)據(jù)庫連接創(chuàng)建、釋放頻繁造成系統(tǒng)資源浪費從而影響系統(tǒng)性能遂蛀,如果使用數(shù)據(jù)庫連接池可解決此問題谭跨。
解決:在SqlMapConfig.xml中配置數(shù)據(jù)連接池,使用連接池管理數(shù)據(jù)庫鏈接李滴。
2螃宙、Sql語句寫在代碼中造成代碼不易維護,實際應用sql變化的可能較大所坯,sql變動需要改變java代碼谆扎。
解決:將Sql語句配置在XXXXmapper.xml文件中與java代碼分離。
3芹助、向sql語句傳參數(shù)麻煩堂湖,因為sql語句的where條件不一定闲先,可能多也可能少,占位符需要和參數(shù)一一對應无蜂。
解決:Mybatis自動將java對象映射至sql語句伺糠,通過statement中的parameterType定義輸入?yún)?shù)的類型。
4酱讶、對結果集解析麻煩退盯,sql變化導致解析代碼變化彼乌,且解析前需要遍歷泻肯,如果能將數(shù)據(jù)庫記錄封裝成pojo對象解析比較方便。
解決:Mybatis自動將sql執(zhí)行結果映射至java對象慰照,通過statement中的resultType定義輸出結果的類型
提出一個需求
MyBatis與HIbernate的不同
Mybatis和hibernate不同灶挟,它不完全是一個ORM框架,因為MyBatis需要程序員自己編寫Sql語句毒租。mybatis可以通過XML或注解方式靈活配置要運行的sql語句稚铣,并將java對象和sql語句映射生成最終執(zhí)行的sql,最后將sql執(zhí)行的結果再映射生成java對象墅垮。
Mybatis學習門檻低惕医,簡單易學,程序員直接編寫原生態(tài)sql算色,可嚴格控制sql執(zhí)行性能抬伺,靈活度高,非常適合對關系數(shù)據(jù)模型要求不高的軟件開發(fā)灾梦,例如互聯(lián)網(wǎng)軟件峡钓、企業(yè)運營類軟件等,因為這類軟件需求變化頻繁若河,一但需求變化要求成果輸出迅速能岩。但是靈活的前提是mybatis無法做到數(shù)據(jù)庫無關性,如果需要實現(xiàn)支持多種數(shù)據(jù)庫的軟件則需要自定義多套sql映射文件萧福,工作量大拉鹃。
Hibernate對象/關系映射能力強,數(shù)據(jù)庫無關性好鲫忍,對于關系模型要求高的軟件(例如需求固定的定制化軟件)如果用hibernate開發(fā)可以節(jié)省很多代碼毛俏,提高效率。但是Hibernate的學習門檻高饲窿,要精通門檻更高煌寇,而且怎么設計O/R映射,在性能和對象模型之間如何權衡逾雄,以及怎樣用好Hibernate需要具有很強的經(jīng)驗和能力才行阀溶。
總之腻脏,按照用戶的需求在有限的資源環(huán)境下只要能做出維護性、擴展性良好的軟件架構都是好架構银锻,所以框架只有適合才是最好永品。
Mapper動態(tài)代理方式開發(fā)
開發(fā)規(guī)范
Mapper接口開發(fā)方法只需要程序員編寫Mapper接口(相當于Dao接口),由Mybatis框架根據(jù)接口定義創(chuàng)建接口的動態(tài)代理對象击纬,代理對象的方法體同上邊Dao接口實現(xiàn)類方法鼎姐。
Mapper接口開發(fā)需要遵循以下規(guī)范:
- 1、 Mapper.xml文件中的namespace與mapper接口的類路徑相同更振。
- 2炕桨、Mapper接口方法名和Mapper.xml中定義的每個statement的id相同
- 3、Mapper接口方法的輸入?yún)?shù)類型和mapper.xml中定義的每個sql 的parameterType的類型相同
- 4肯腕、Mapper接口方法的輸出參數(shù)類型和mapper.xml中定義的每個sql的resultType的類型相同
創(chuàng)建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="cn.probuing.mybatisintro.mapper.UserMapper">
<!--根據(jù)id查詢用戶-->
<select id="queryUserById" parameterType="int"
resultType="cn.probuing.mybatisintro.pojo.User">
select *
from user
where id = #{id}
</select>
<!--根據(jù)用戶名查詢用戶-->
<select id="queryUserByName" parameterType="String"
resultType="cn.probuing.mybatisintro.pojo.User">
select *
from user
where username like '%${value}%'
</select>
</mapper>
創(chuàng)建接口UserMapper
public interface UserMapper {
public User queryUserById(int id);
public List<User> queryUserByName(String userName);
}
核心配置文件加載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">
<!--namespace命名空間 用于隔離sql -->
<mapper namespace="cn.probuing.mybatisintro.mapper.UserMapper">
<!--根據(jù)id查詢用戶-->
<select id="queryUserById" parameterType="int"
resultType="cn.probuing.mybatisintro.pojo.User">
select *
from user
where id = #{id}
</select>
<!--根據(jù)用戶名查詢用戶-->
<select id="queryUserByName" parameterType="String"
resultType="cn.probuing.mybatisintro.pojo.User">
select *
from user
where username like '%${value}%'
</select>
</mapper>
測試代碼
/**
* 根據(jù)id查詢用戶
*/
@Test
public void testQueryUserById() throws IOException {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sessionFactory = builder.build(Resources.getResourceAsStream("SqlMapConfig.xml"));
SqlSession sqlSession = sessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.queryUserById(31);
System.out.println(user);
}
/**
* 根據(jù)name查詢用戶列表
* @throws IOException
*/
@Test
public void testQueryUserByname() throws IOException {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = builder.build(Resources.getResourceAsStream("SqlMapConfig.xml"));
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = userMapper.queryUserByName("王");
for (User user : userList) {
System.out.println(user);
}
}
SqlMapConfig.xml配置文件詳解
配置內(nèi)容
SqlMapConfig.xml中配置的內(nèi)容和順序如下
- properties(屬性)
- settings(全局配置參數(shù))
- typeAliases(類型別名)
- typeHandlers(類型處理器)
- objectFactory(對象工廠)
- plugins(插件)
- environments(環(huán)境集合屬性對象)
- environment(環(huán)境子屬性對象)
- transactionManager(事務管理)
- dataSource(數(shù)據(jù)源)
- environment(環(huán)境子屬性對象)
- mappers(映射器)
properties(屬性)
- db.properties 配置文件內(nèi)容
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
- SqlMapConfig.xml
<!-- 是用resource屬性加載外部配置文件 -->
<properties resource="db.properties">
<!-- 在properties內(nèi)部用property定義屬性 -->
<!-- 如果外部配置文件有該屬性献宫,則內(nèi)部定義屬性被外部屬性覆蓋 -->
<property name="jdbc.username" value="root123" />
<property name="jdbc.password" value="root123" />
</properties>
<environments default="development">
<environment id="development">
<!-- 使用jdbc事務管理 -->
<transactionManager type="JDBC" />
<!-- 數(shù)據(jù)庫連接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 加載映射文件 -->
<mappers>
<mapper resource="sqlmap/User.xml" />
<mapper resource="mapper/UserMapper.xml" />
</mappers>
tips
MyBatis將按照下面的順序來加載屬性
- 在properties元素體內(nèi)定義的屬性首先被讀取
- 然后會讀取properties元素中resource或url加載的屬性,它會覆蓋已讀取的同名屬性
typeAliases(類型別名)
mybatis支持別名
別名 映射的類型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
map Map
自定義別名
- 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>
<!-- 是用resource屬性加載外部配置文件 -->
<properties resource="db.properties">
<!-- 在properties內(nèi)部用property定義屬性 -->
<property name="jdbc.username" value="root123" />
<property name="jdbc.password" value="root123" />
</properties>
<typeAliases>
<!-- 單個別名定義 -->
<typeAlias alias="user" type="cn.itcast.mybatis.pojo.User" />
<!-- 批量別名定義实撒,掃描整個包下的類怪瓶,別名為類名(大小寫不敏感) -->
<package name="cn.itcast.mybatis.pojo" />
<package name="其它包" />
</typeAliases>
<!-- 和spring整合后 environments配置將廢除 -->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事務管理 -->
<transactionManager type="JDBC" />
<!-- 數(shù)據(jù)庫連接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 加載映射文件 -->
<mappers>
<mapper resource="sqlmap/User.xml" />
<mapper resource="mapper/UserMapper.xml" />
</mappers>
</configuration>
在mapper.xml配置文件中憾赁,就可以使用設置的別名了
別名大小寫不敏感
mappers(映射器)
Mapper配置的幾種方法
- <mapper resource=""/>
使用相對于類路徑的資源(現(xiàn)在的使用方式)
<mapper resource="sqlmap/User.xml" />
- <mapper class=""/> 使用mapper類接口路徑
<mapper class="cn.itcast.mybatis.mapper.UserMapper"/>
此方法要求mapper接口名稱和mapper映射文件名稱相同,且放在同一個目錄中
- <package name=""/> 注冊指定包下的所有mapper接口
<package name="cn.probuing.xxx"/>
此方法要求mapper接口名稱和mapper映射文件名稱相同,且放在同一個目錄中
Mybatis輸入映射和輸出映射
輸出簡單類型
輸出POJO對象
開發(fā)中通過可以使用pojo傳遞查詢條件
查詢條件可能是綜合的查詢條件蜜唾,不僅包括用戶的查詢條件還包括其它的查詢條件
包裝對象:Pojo類中的一個屬性是另外一個pojo
創(chuàng)建包裝類對象QueryVo
public class QueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
創(chuàng)建映射文件Mapper.xml文件
其中輸入?yún)?shù)為包裝條件對象QueryVo 輸出對象為User泛型
<!--根據(jù)用戶名查詢數(shù)據(jù)-->
<select id="selectListByUserNameQueryVo" parameterType="QueryVo" resultType="cn.probuing.mybatisintro.pojo.User">
SELECT * FROM user where username LIKE '%${user.username}'
</select>
Mapper接口
在UserMapper接口中添加方法
/**
* 根據(jù)包裝條件查詢用戶列表數(shù)據(jù)
*
* @param queryVo
* @return
*/
public List<User> queryUserByQueryVo(QueryVo queryVo);
測試方法
@Test
public void testQueryVo() throws IOException {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = builder.build(Resources.getResourceAsStream("SqlMapConfig.xml"));
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
QueryVo queryVo = new QueryVo();
User user = new User();
user.setUsername("五");
queryVo.setUser(user);
List<User> list = userMapper.selectListByUserNameQueryVo(queryVo);
for (User user1 : list) {
System.out.println(user1);
}
}
resultMap
在Mapper文件中造壮,resultType可以指定將查詢結果映射為POJO或颊,前提必須是POJO和sql查詢的列名一致方可映射成功咨油。
如果sql查詢字段名和POJO的屬性名不一致,可以通過resultMap將字段名和屬性名作為一個指定的對應關系原在。resultMap實質上還需要將查詢結果映射到POJO對象中友扰。
resultMap可以實現(xiàn)將查詢結果映射為復雜類型的POJO
創(chuàng)建一個POJO
package cn.probuing.mybatisintro.pojo;
import java.io.Serializable;
import java.util.Date;
public class Orders implements Serializable{
@Override
public String toString() {
return "Orders [id=" + id + ", userId=" + userId + ", number=" + number + ", createtime=" + createtime
+ ", note=" + note + "]";
}
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//附加對象 用戶對象
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number == null ? null : number.trim();
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note == null ? null : note.trim();
}
}
該pojo中 order中的userid與數(shù)據(jù)庫中表對應的查詢列不一致
創(chuàng)建OrderMapper.xml映射文件
<mapper namespace="cn.probuing.mybatisintro.mapper.OrderMapper">
<!--
id 對應指定的resultMap標識
type 指定映射到哪一個pojo上
-->
<resultMap id="orderResultMap" type="orders">
<!--id 定義主鍵 如果是多個字段 則定義多個id
標簽中的property 表示 指定映射到pojo的哪個屬性
標簽中的column 表示 指定映射到數(shù)據(jù)庫中的列名
-->
<id property="id" column="id"/>
<!--普通屬性使用result定義-->
<result property="userId" column="user_id"/>
<result property="number" column="number"/>
<result property="createtime" column="createtime"/>
<result property="note" column="note"/>
</resultMap>
<!--resultMap標簽指定一個ResultMap的標識-->
<select id="queryOrderList" resultMap="orderResultMap">
SELECT id, user_id,
number,
createtime, note FROM `orders`
</select>
</mapper>
測試代碼
@Test
public void testResultMapQuery() throws IOException {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = builder.build(Resources.getResourceAsStream("SqlMapConfig.xml"));
SqlSession sqlSession = sqlSessionFactory.openSession();
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
List<Orders> orderList = orderMapper.queryOrderList();
for (Orders orders : orderList) {
System.out.println(orders);
}
}
動態(tài)SQL
通過Mybatis提供的各種標簽方法實現(xiàn)動態(tài)拼接SQL
if標簽
編寫mapper.xml文件
<!--動態(tài)標簽-->
<select id="queryUserByWhere" parameterType="user" resultType="user">
<!-- 考慮到sex 和username不一定同時存在 所以加入if標簽進行判斷 -->
SELECT * FROM user
WHERE 1=1
<if test="sex !=null and sex !=''">
and sex = #{sex}
</if>
<if test="username !=null and username !=''">
and username LIKE "%${username}%"
</if>
</select>
上面這種判斷 還是存在where 1=1 的情況,這種情況顯然還是很麻煩的 庶柿,下面我們使用where標簽對上面的判斷進行改造
where標簽
mapper.xml文件
<select id="queryUserByWhere" parameterType="user" resultType="user">
<!-- 考慮到sex 和username不一定同時存在 所以加入if標簽進行判斷 -->
SELECT * FROM user
<where>
<if test="sex !=null and sex !=''">
and sex = #{sex}
</if>
<if test="username !=null and username !=''">
and username LIKE "%${username}%"
</if>
</where>
</select>
where標簽會自動添加where條件村怪,同時會處理sql語句中的第一個and關鍵字
sql片段
sql中可將重復的sql提取出來,使用時用Include引用浮庐,最終達到sql重用的目的
上面的sql提取出來后
<!-- 根據(jù)條件查詢用戶 -->
<select id="queryUserByWhere" parameterType="user" resultType="user">
<!-- SELECT id, username, birthday, sex, address FROM `user` -->
<!-- 使用include標簽加載sql片段甚负;refid是sql片段id -->
SELECT <include refid="userFields" /> FROM `user`
<!-- where標簽可以自動添加where關鍵字,同時處理sql語句中第一個and關鍵字 -->
<where>
<if test="sex != null">
AND sex = #{sex}
</if>
<if test="username != null and username != ''">
AND username LIKE
'%${username}%'
</if>
</where>
</select>
<!-- 聲明sql片段 -->
<sql id="userFields">
id, username, birthday, sex, address
</sql>
foreach標簽
向sql中傳遞數(shù)組或list mybatis使用foreach解析
改造QueryVo
在QueryVo中加入List代表多個id的集合
public class QueryVo implements Serializable {
private User user;
private List<Integer> ids;
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
Mapper.xml文件
<!--根據(jù)ids查詢用戶-->
<select id="queryUserByIds" parameterType="queryVo" resultType="user">
SELECT * FROM user
<where>
<!--
foreach標簽
collection:要遍歷的集合审残,在這里是QueryVo中的ids屬性
直接傳遞數(shù)組時collection指定array
直接傳遞list時collection指定list
item:遍歷的項目
open:在前面添加的sql片段
close:在結尾處添加的sql片段
separator:指定遍歷的元素之間使用的分隔符
-->
<foreach collection="ids" item="item" open="id in (" close=")" separator=",">
#{item}
</foreach>
</where>
</select>
測試方法
@Test
public void testQueryByIds() throws IOException {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = builder.build(Resources.getResourceAsStream("SqlMapConfig.xml"));
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
QueryVo queryVo = new QueryVo();
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(10);
list.add(24);
queryVo.setIds(list);
List<User> users = userMapper.queryUserByIds(queryVo);
for (User user : users) {
System.out.println(user);
}
}
一對一查詢
使用resultMap
改造pojo類
在Order類中加入User屬性梭域,user屬性中用于存儲關聯(lián)查詢的用戶信息,對于訂單來說訂單關聯(lián)查詢用戶是一對一關系搅轿,所以這里使用單個User對象存儲關聯(lián)查詢的用戶信息
public class Orders implements Serializable{
@Override
public String toString() {
return "Orders [id=" + id + ", userId=" + userId + ", number=" + number + ", createtime=" + createtime
+ ", note=" + note + "]";
}
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//附加對象 用戶對象
private User user;
}
Mapper.xml
<resultMap id="orderUserResultMap" type="orders">
<!--映射數(shù)據(jù)庫主鍵 id-->
<id property="id" column="id"/>
<result property="userId" column="user_id"/>
<result property="number" column="number"/>
<result property="createtime" column="createtime"/>
<result property="note" column="note"/>
<!--一對一屬性映射-->
<association property="user" javaType="user">
<id property="id" column="user_id"/>
<result property="username" column="username"/>
<result property="address" column="address"/>
</association>
</resultMap>
<!--一對一關聯(lián)病涨,查詢訂單,訂單內(nèi)部包含用戶屬性-->
<select id="queryOrderUserResultMap" resultMap="orderUserResultMap">
SELECT
o.id,
o.user_id,
o.number,
o.createtime,
o.note,
u.username,
u.address
FROM
`orders` o
LEFT JOIN `user` u ON o.user_id = u.id
</select>
上面的配置文件中 左關聯(lián)查詢時 對應映射的類與數(shù)據(jù)庫查詢列不一致 所以使用resultMap映射
Orders中有User屬性璧坟,所以需要使用一對一映射User 使用resultMap的association標簽映射User屬性既穆,在association標簽下 再分別映射user對象的屬性 其中指定的property是user對象的屬性名 column是對應數(shù)據(jù)庫列的名稱
測試代碼
@Test
public void testQueryByResultMap() throws IOException {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = builder.build(Resources.getResourceAsStream("SqlMapConfig.xml"));
SqlSession sqlSession = sqlSessionFactory.openSession();
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
List<Orders> orders = orderMapper.queryOrderUserResultMap();
for (Orders order : orders) {
System.out.println(order);
}
}
一對多查詢
修改POJO User類
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;// 地址
private List<Orders> ordersList;
public List<Orders> getOrdersList() {
return ordersList;
}
public void setOrdersList(List<Orders> ordersList) {
this.ordersList = ordersList;
}
}
Mapper.xml 映射文件
<resultMap type="User" id="user">
<id column="id" property="id"/>
<result column="username" property="username"/>
<!-- 一對多 -->
<collection property="orders" ofType="Orders">
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
</collection>
</resultMap>
<select id="queryUserOrder" resultMap="user">
SELECT
o.id,
o.user_id,
o.number,
o.createtime,
u.username
FROM user u
left join orders o
on o.user_id = u.id
</select>
Mybatis整合Spring
整合思路
- SqlSessionFactory對象應該放到spring容器中作為單例存在赎懦。
- 傳統(tǒng)dao的開發(fā)方式中,應該從spring容器中獲得sqlsession對象幻工。
- Mapper代理形式中励两,應該從spring容器中直接獲得mapper的代理對象。
- 數(shù)據(jù)庫的連接以及數(shù)據(jù)庫連接池事務管理都交給spring容器來完成囊颅。
整合需要的jar包
spring的jar包
Mybatis的jar包
Spring+mybatis的整合包当悔。
Mysql的數(shù)據(jù)庫驅動jar包。
數(shù)據(jù)庫連接池的jar包踢代。
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>
<!-- 設置別名 -->
<typeAliases>
<!-- 2. 指定掃描包盲憎,會把包內(nèi)所有的類都設置別名,別名的名稱就是類名奸鬓,大小寫不敏感 -->
<package name="cn.probuing.mybatisspring.pojo"/>
</typeAliases>
</configuration>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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.xsd">
<!--加載配置文件-->
<context:property-placeholder location="classpath:config/db.properties"/>
<!--配置數(shù)據(jù)庫連接池-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置sqlsessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--配置mybatis核心配置文件-->
<property name="configLocation" value="classpath:config/SqlMapConfig.xml"/>
<!--配置數(shù)據(jù)源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置UserMapper-->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<!--配置mapper接口-->
<property name="mapperInterface" value="cn.probuing.mybatisspring.mapper.UserMapper"/>
<!--配置SqlSessionFactory工廠-->
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
</beans>
db.properties
Mapper接口
public interface UserMapper {
public User findUserById(Integer id);
}
UserMapper.xml映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.probuing.mybatisspring.mapper.UserMapper">
<select id="findUserById" parameterType="Integer" resultType="User">
SELECT *
FROM user
where id = #{v}
</select>
</mapper>
測試代碼
@Test
public void testQueryById() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("config/applicationContext.xml");
UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
User user = userMapper.findUserById(10);
System.out.println(user);
}
在存在多個mapper的時候 在spring中都需要制定具體的mapper 這種方式在我們開發(fā)中是很麻煩的焙畔,所以在這種時候我們引入掃描包形式配置mapper
掃描包形式配置mapper
在配置的時候需要制定 MapperScannerConfigurer 在property中指定掃描的基礎包
由于工廠已經(jīng)實例化 所以不需要指定工廠 MapperScannerConfigurer也能找到工廠
<!--包掃描形式配置mapper-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.probuing.mybatisspring.mapper"/>
</bean>
Mybatis逆向工程
使用官方網(wǎng)站提供的Mapper自動生成工具 mybatis-generator-core來生成pojo類和Mapper映射文件
導入逆向工程
修改配置文件
<?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>
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自動生成的注釋 true:是 : false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--數(shù)據(jù)庫連接的信息:驅動類掸读、連接地址串远、用戶名、密碼 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root" password="root">
</jdbcConnection>
<!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver" connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg"
userId="yycg" password="yycg"> </jdbcConnection> -->
<!-- 默認false儿惫,把JDBC DECIMAL 和 NUMERIC 類型解析為 Integer澡罚,為 true時把JDBC DECIMAL
和 NUMERIC 類型解析為java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成PO類的位置 -->
<javaModelGenerator targetPackage="cn.itcast.ssm.po"
targetProject=".\src">
<!-- enableSubPackages:是否讓schema作為包的后綴 -->
<property name="enableSubPackages" value="false" />
<!-- 從數(shù)據(jù)庫返回的值被清理前后的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:mapper映射文件生成的位置 -->
<sqlMapGenerator targetPackage="cn.itcast.ssm.mapper"
targetProject=".\src">
<!-- enableSubPackages:是否讓schema作為包的后綴 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="cn.itcast.ssm.mapper" targetProject=".\src">
<!-- enableSubPackages:是否讓schema作為包的后綴 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 指定數(shù)據(jù)庫表 -->
<table schema="" tableName="user"></table>
<table schema="" tableName="order"></table>
</context>
</generatorConfiguration>
生成逆向工程代碼 執(zhí)行工程main主函數(shù)
代碼生成在工程目錄下
注意
- 逆向工程生成的代碼只能做單表查詢
- 不能在生成的代碼上進行擴展,因為如果數(shù)據(jù)庫變更肾请,需要重新使用逆向工程生成代碼留搔,原來編寫的代碼就被覆蓋了。
- 一張表會生成4個文件