花了幾個小時整理了一下MyBaits的使用,在這裏總結和分享一下。
MyBatis的官網是這麼介紹的:
MyBatis 是支持定製化 SQL、存儲過程以及高級映射的優秀的持久層框架。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 可以對配置和原生Map使用簡單的 XML 或註解,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對象)映射成數據庫中的記錄。
簡單明瞭,這介紹很不錯。但是這樣,往往容易會把它複雜化。
下面先來一個簡單易懂的demo,演示往mybatis數據庫中的userinfo表插入一條數據。項目的文件架構圖如下:
MyBatis框架所要用到的jar包有:asm-3.3.1 cglib-2.2.2 javassist-3.17.1-GA log4j-1.2.17 mybatis-3.2.2 mysql-connector-java-5.1.7-bin slf4j-api-1.7.5 slf4j-log4j12-1.7.5
創建entity實體類UserInfo:
package yzr.entity;
import java.io.Serializable;
public class UserInfo implements Serializable {
private int userId;
private String userName;
private String eMail;
public UserInfo(){}
public int getUserId() {
return userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String geteMail() {
return eMail;
}
public void seteMail(String eMail) {
this.eMail = eMail;
}
@Override
public String toString() {
return "UserInfo [userId=" + userId + ", userName=" + userName
+ ", eMail=" + eMail + "]";
}
public UserInfo(String UserName,String EMail){
this.userName=UserName;
this.eMail=EMail;
}
}
爲UserInfo實體類創建一個映射文件:UserInfoMapper.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="yzr.entity.UserInfo">
<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="512"></cache>
<!-- 定義插入的sql語句,通過命名空間+id方式被定位 -->
<insert id="insert" parameterType="yzr.entity.UserInfo">
<![CDATA[
insert into
userinfo(username,email) values(#{userName},#{eMail});
]]>
</insert>
<!-- 定義update的sQL語句 -->
<update id="update" parameterType="yzr.entity.UserInfo">
<![CDATA[update UserInfo set
username=#{userName},email=#{eMail} where userid=#{userId}
]]>
</update>
<!-- 定義刪除的SQL -->
<delete id="delete" parameterType="Integer">
delete from userinfo where
userid=#{userId}
</delete>
<!-- 一般在查詢時使用 -->
<resultMap type="yzr.entity.UserInfo" id="userInfoResultMap">
<id property="userId" column="UserId" />
<result property="userName" column="UserName" />
<result property="eMail" column="EMail" />
</resultMap>
<!-- 省略其它的配置信息 -->
<!-- 返回單條記錄,表字段和對應實體屬性命名一致時可以不使用resultMap屬性配置,直接使用resultType="返回的全類名或別名",建議使用前者;查詢結果爲所有字段時,也可以用*表示 -->
<select id="selectOne" parameterType="int" resultMap="userInfoResultMap" useCache="true">
select
userid, username,email from userinfo where userid=#{userId}
</select>
<!-- 返回多條記錄,返回結果是集合元素的類型;參數也可以通過Map等方式封裝 -->
<select id="selectList" parameterType="Map" resultMap="userInfoResultMap">
select *
from userinfo where username like #{userName}
</select>
<!-- 動態IF條件 -->
<select id="selectListUseIf" parameterType="yzr.entity.UserInfo"
resultMap="userInfoResultMap">
select * from userinfo where 1=1
<if test="userId!=null">
and userid=#{userId}
</if>
<if test="userName!=null">
and username=#{userName}
</if>
<if test="eMail!=null">
and email=#{eMail}
</if>
</select>
<!-- 動態Where條件 ,一般也需要與if結合使用,與純if比較,省略了where 1=1 -->
<select id="selectListUseWhere" parameterType="yzr.entity.UserInfo"
resultMap="userInfoResultMap">
select * from userinfo
<where>
<if test="userId!=null">
and userid=#{userId}
</if>
<if test="userName!=null">
and username=#{userName}
</if>
<if test="eMail!=null">
and email=#{eMail}
</if>
</where>
</select>
<!-- 動態choose條件 ,如下配置,可以完成沒有選擇條件時,查找不出任何數據 -->
<select id="selectListUseChoose" parameterType="yzr.entity.UserInfo"
resultMap="userInfoResultMap">
select * from userinfo where 1=1
<choose>
<when test="userId!=null">and userid=#{userId}</when>
<when test="userName!=null">and username=#{userName}</when>
<when test="eMail!=null">and email=#{eMail}</when>
<otherwise>and !1 = 1</otherwise>
</choose>
</select>
<!--動態set語句可以用來更新數據 -->
<update id="updateUseSet" parameterType="yzr.entity.UserInfo">
update userinfo
<set>
<if test="userName!=null">username=#{userName},</if>
<if test="eMail!=null">email=#{eMail},</if>
</set>
where dept_id=#{deptId}
</update>
<!-- 動態in寫法,resultMap的值是指集合裏元素的類型,parameterType不用指定 -->
<select id="selectListUseForeach" parameterType="Integer[]"
resultMap="userInfoResultMap">
select * from userinfo where userid in
<!-- collection="array或list",array用來對應參數爲數組,list對應參數爲 集合 -->
<foreach collection="array" item="deptId" open="(" separator=","
close=")">
#{userId}
</foreach>
</select>
<!-- 使用include語句動態插入表的字段及對應的值 -->
<sql id="key">
<!--suffixOverrides="," 可以忽略最後“,”號 -->
<trim suffixOverrides=",">
<if test="userName!=null">
username,
</if>
<if test="eMail!=null">
email,
</if>
</trim>
</sql>
<sql id="value">
<trim suffixOverrides=",">
<if test="userName!=null">
#{userName},
</if>
<if test="eMail!=null">
#{eMail},
</if>
</trim>
</sql>
<insert id="insertUseInclude" parameterType="yzr.entity.UserInfo">
insert into userinfo(
<include refid="key" />
) values(
<include refid="value" />
)
</insert>
<sql id="Insertkey">
<!--suffixOverrides="," 可以忽略最後“,”號 -->
<trim suffixOverrides=",">
username,
email,
</trim>
</sql>
<insert id="insertUserInfoList">
insert into userinfo(
<include refid="Insertkey" />
) values
<foreach collection="list" item="item" separator=",">
(#{item.userName},#{item.eMail})
</foreach>
</insert>
<delete id="deleteUserInfoList">
delete from userinfo where userid in
<foreach collection="list" item="item" open="(" close=")"
separator=",">
#{item}
</foreach>
</delete>
<update id="updateUserInfoList">
<foreach collection="list" item="user" separator=";">
update userinfo
<set>
<if test="user.userName!=null">username=#{user.userName},</if>
<if test="user.eMail!=null">email=#{user.EMail},</if>
</set>
where userId=#{user.userId}
</foreach>
</update>
</mapper>
在Dao中創建個userInfoDao:
package yzr.dao;
import java.io.IOException;
import java.io.Reader;
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 yzr.entity.UserInfo;
public class UserInfoDao {
public int insert(UserInfo user) {
/*
* 1.讀取配置信息 2.構建session工廠 3.創建session 4.啓動事務(可選) 5.數據處理 6.提交事務、回滾事務(可選)
* 7.關閉session
*/
int i = 0;
SqlSession session = null;
String config = "myBatis-config.xml";
Reader reader = null;
try {
reader = Resources.getResourceAsReader(config);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(reader);
session = sqlSessionFactory.openSession();
// 事務默認自動啓動
// SQL映射文件定義的命名空間+SQL語句的ID定位SQL語句,例如下的:cn.itcast.entity.DeptMapper.insert
i = session.insert("yzr.entity.UserInfo.insert", user);
session.commit();
} catch (IOException e) {
e.printStackTrace();
session.rollback();
} finally {
// 關閉reader對象,這裏略
session.close();
}
return i;
}
}
最後一步,也是關鍵一步,配置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>
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<!--可以設置多個運行環境,滿足不同需要,例如 開發、測試、生產環境上有不同一配置 -->
<environments default="development">
<environment id="development">
<!-- 事務管理類型主要有jdbc和managed,前者依賴於數據源獲得的連接,後者依賴於容器 -->
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<!-- 如果數據庫設置爲UTF-8,則URL參數連接需要添加?useUnicode=true&characterEncoding=UTF-8,如下 -->
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true" />
<property name="username" value="root" />
<property name="password" value="677714" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="yzr/entity/UserInfoMapper.xml" />
</mappers>
</configuration>
那現在就可以測試一下了:
@Test
public void testInsert() {
UserInfo user=new UserInfo();
user.setUserName("YZR");
user.seteMail("[email protected]");
int i=userInfoDao.insert(user);
System.out.println("受影響行數:"+i);
}
在UserInfoDao中編寫了獲取資源配置文件以及創建myBatis的sqlSession,下面優化一下,編寫一個myBatisUtil幫助類:
package yzr.util;
import java.io.IOException;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisUtil {
private static final ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>();
private static SqlSessionFactory sessionFactory;
private static String CONFIG_FILE_LOCATION = "myBatis-config.xml";
static {
try {
buildSessionFactory();
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
private MyBatisUtil() {
}
/**
* Returns the ThreadLocal Session instance. Lazy initialize the
* <code>SessionFactory</code> if needed.
*
* @return Session
* @throws Exception
*/
public static SqlSession getSession() throws Exception {
SqlSession session =threadLocal.get();
if (session == null) {
if (sessionFactory == null) {
buildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
/**
* build session factory
*
*/
public static void buildSessionFactory() {
Reader reader = null;
try {
reader = Resources.getResourceAsReader(CONFIG_FILE_LOCATION);
sessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* Close the single session instance.
*
* @throws Exception
*/
public static void closeSession() {
SqlSession session = (SqlSession) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.close();
}
}
/**
* return session factory
*
*/
public static SqlSessionFactory getSessionFactory() {
return sessionFactory;
}
}
在myBatis中對象關聯關係中用兩個節點來描述:association和collection。
collection用於表示一對多,或者多對多。association用於表示多對一,或者一對一。
舉個列子,部門和員工的關係使用association來關聯:
Deptmapper.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="yzr.entity.DeptMapper">
<!-- 定義插入的sql語句,通過命名空間+id方式被定位 -->
<insert id="insert" parameterType="yzr.entity.Dept">
insert into
dept(deptname) values(#{deptName});
</insert>
<!-- 一般在查詢時使用 -->
<resultMap type="yzr.entity.Dept" id="deptResultMap">
<id property="deptId" column="deptId" />
<result property="deptName" column="DeptName" />
</resultMap>
<!-- 返回多條記錄,返回結果是集合元素的類型;參數也可以通過Map等方式封裝 -->
<select id="selectList" parameterType="Map" resultMap="deptResultMap">
select *
from dept where deptname like #{deptName}
</select>
</mapper>
EmployeesMapper.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="yzr.entity.EmployeesMapper">
<!-- 定義插入的sql語句,通過命名空間+id方式被定位 -->
<insert id="insert" parameterType="yzr.entity.Employees">
insert into
employees(empname,deptid) values(#{empName},#{dept.deptId});
</insert>
<!-- 一般在查詢時使用 -->
<resultMap type="yzr.entity.Employees" id="employeesResultMap">
<id property="empId" column="EmpId" />
<result property="empName" column="EmpName" />
<association property="dept" column="DeptId" javaType="yzr.entity.Dept" resultMap="yzr.entity.DeptMapper.deptResultMap"></association>
</resultMap>
<!-- 返回多條記錄,返回結果是集合元素的類型;參數也可以通過Map等方式封裝 -->
<select id="selectList" parameterType="Map" resultMap="employeesResultMap">
select emp.*,dp.*
from employees emp inner join dept dp on emp.deptid=dp.deptId where empname like #{empName}
</select>
</mapper>
測試一下:
@SuppressWarnings({ "rawtypes", "unchecked" })
@Test
public void testAssoication(){
SqlSession session=null;
try {
session=MyBatisUtil.getSession();
Map map =new HashMap();
map.put("empName", "YZR");
List<Employees> list=session.selectList("yzr.entity.EmployeesMapper.selectList",map);
System.out.println(list);
} catch (Exception e) {
e.printStackTrace();
}
}
結果:[Employees [empId=2, empName=YZR, dept=Dept [deptId=3, deptName=研發部]], Employees [empId=3, empName=YZR, dept=Dept [deptId=3, deptName=研發部]]]
同理,使用collection可以雙向獲取對象集合,比如學生和教師的關係。某一教師下的所有學生,學生的老師。
StudentMapper.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="yzr.entity.StudentMapper">
<!-- 一般在查詢時使用 -->
<resultMap type="yzr.entity.Student" id="StudentResultMap">
<id property="sId" column="sId" />
<result property="sName" column="sName" />
<association property="teacher" column="tId" javaType="yzr.entity.Teacher" resultMap="yzr.entity.TeacherMapper.TeacherResultMap"></association>
</resultMap>
<!-- 返回多條記錄,返回結果是集合元素的類型;參數也可以通過Map等方式封裝 -->
<select id="selectList" parameterType="Map" resultMap="StudentResultMap">
select s.*,t.*
from student s inner join teacher t on s.tid=t.tid where sName like #{sName}
</select>
</mapper>
Teachermapper.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="yzr.entity.TeacherMapper">
<!-- 一般在查詢時使用 -->
<resultMap type="yzr.entity.Teacher" id="TeacherResultMap">
<id property="tId" column="tId" />
<result property="tName" column="tName" />
</resultMap>
<resultMap type="yzr.entity.Teacher" id="TeacherExtResultMap" extends="TeacherResultMap">
<collection property="students" ofType="yzr.entity.Student" resultMap="yzr.entity.StudentMapper.StudentResultMap"></collection>
</resultMap>
<!-- 返回多條記錄,返回結果是集合元素的類型;參數也可以通過Map等方式封裝 -->
<select id="selectList" parameterType="Map" resultMap="TeacherExtResultMap">
select * from Teacher t inner join student s on s.tid=t.tid where t.tname like #{tName}
</select>
</mapper>
測試:
@Test
public void testCollection(){
SqlSession session=null;
try {
session=MyBatisUtil.getSession();
Map map =new HashMap();
map.put("sName", "YZR");
List<Student> list=session.selectList("yzr.entity.StudentMapper.selectList",map);
System.out.println(list);
Map map2 =new HashMap();
map2.put("tName", "LYF");
List<Teacher> list2=session.selectList("yzr.entity.TeacherMapper.selectList",map2);
System.out.println(list2);
} catch (Exception e) {
e.printStackTrace();
}
}
結果:
[Student [sId=1, sName=YZR, teacher=Teacher [tId=1, tName=LYF, students=null]]]
[Teacher [tId=1, tName=LYF, students=[Student [sId=1, sName=YZR, teacher=Teacher [tId=1, tName=LYF, students=null]]]]]
如果在你運行過程中出現如下錯誤:
<mappers>
<mapper resource="yzr/entity/UserInfoMapper.xml" />
<mapper resource="yzr/entity/EmployeesMapper.xml" />
<mapper resource="yzr/entity/DeptMapper.xml" />
<mapper resource="yzr/entity/StudentMapper.xml" />
<mapper resource="yzr/entity/TeacherMapper.xml" />
</mappers>
在進行UserInfo的批量更新時需要注意,在datasource中的url需要加上:
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true" />
sping和myBatis的整合:
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- 配置數據源,記得去掉myBatis-config.xml的數據源相關配置 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8" />
<property name="user" value="root" />
<property name="password" value="root" />
</bean>
<!-- 配置session工廠 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:myBatis-config.xml" />
<!-- 配置掃描式加載SQL映射文件 -->
<property name="mapperLocations" value="classpath:cn/itcast/entity/*.xml"/>
</bean>
<!-- 配置事務管理器,管理數據源事務處理-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置SessionTemplate,已封裝了繁瑣的數據操作-->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
</beans>
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>
<typeAliases>
<typeAlias type="" alias="" />
</typeAliases>
</configuration>