MyBatis

花了幾個小時整理了一下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]]]]]

如果在你運行過程中出現如下錯誤:

 Mapped Statements collection does not contain value   
檢查一下是否在myBatis-config.xml包含了相應創建的mapper文件,:

	<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&amp;characterEncoding=UTF-8&amp;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>










發佈了55 篇原創文章 · 獲贊 64 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章