1. 程式人生 > >mybatis框架--學習筆記(下)

mybatis框架--學習筆記(下)

8、高階對映:

(1)一對一查詢:

①使用resultType:

<!-- 一對一查詢:resultType -->
<select id="findOrdersUser" resultType="com.zwp.po.OrdersCustom">
	select orders.*,
		user.username,
		user.sex,
		user.address
 	from orders,user
	where orders.user_id=user.id
</select>
//Orders的擴充套件類
public class OrdersCustom extends Orders{
	//新增用屬性
	private String username;
	private String sex;
	private String address;
	//下面省略get和set方法..
}

②使用resultMap:(association)

使用resultMap將查詢結果中的訂單資訊對映到Orders物件中,在orders類中新增User屬性,將關聯查詢出來的使用者資訊對映到orders物件中的user屬性中。

public class Orders {
    private Integer id;
    private Integer userId;
    private String number;
    private Date createtime;
    private String note;
    
    private User user;//在Orders中新增User屬性,一對一
    
    //下面省略get和set方法
}
	<!-- 一對一查詢:resultMap
		使用resultMap將查詢結果中的訂單資訊對映到Orders物件中,在orders類中新增User屬性,
	 	將關聯查詢出來的使用者資訊新增到orders物件的user屬性中-->
	 <resultMap type="com.zwp.po.Orders" id="OrdersUserResultMap">
	 	<!-- 配置訂單資訊的對映 -->
	 	<!-- id:指定查詢列中的唯一標識,即訂單資訊的唯一標識,如果有多個列組成唯一標識,則配置多個id
	 		column:查詢出來的列名; property:對映到Orders的哪個屬性
	 	 -->
	 	<id column="id" property="id" />
	 	<result column="user_id" property="userId" />
	 	<result column="number" property="number" />
	 	<result column="createtime" property="createtime" />
	 	<result column="note" property="note" />
	 	
	 	<!-- 配置對映的關聯的使用者資訊 -->
	 	<!-- association:用於對映關聯查詢的單個物件資訊
	 	property:要將關聯查詢的使用者資訊對映到Orders中的哪個屬性 -->
	 	<association property="user" javaType="com.zwp.po.User">
	 		<!-- id:關聯查詢的唯一標識,column:指定唯一標識的使用者的列 -->
	 		<id column="user_id" property="id" />
		 	<result column="username" property="username" />
		 	<result column="sex" property="sex" />
		 	<result column="address" property="address" />
	 	</association> 
	 </resultMap>	
	 <select id="findOrdersUserResultMap" resultMap="OrdersUserResultMap">
		 select orders.*,
				user.username,
				user.sex,
				user.address
	 	from orders,user
		where orders.user_id=user.id
	 </select>

小結:實現一對一查詢:

resultyType:使用resultType實現較為簡單,如果pojo中沒有包括查詢出來的列名,需要增加列名對應的屬性,即可完成對映。如果沒有查詢結果的特殊要求,建議使用resultyType。

resultMap:需要 單獨定義resultMap,實現有點麻煩,如果有對查詢結果有特殊要求,使用resultMap可以完成將關聯查詢對映到pojo的屬性中。

resultMap可以實現延時載入,resultyType無法實現延時載入。

(2)一對多查詢:(collection)

要求:對orders對映不能出現重複記錄。

思路:在order.java類中新增List<OrderDetail>orderDetails屬性,最終會將訂單資訊對映到orders中,訂單所對應的訂單明細對映到orders中的orderDetails屬性中。

public class Orders {
    private Integer id;
    private Integer userId;
    private String number;
    private Date createtime;
    private String note;
    
    private User user;//使用者資訊,一對一
    
    //訂單明細:一對多
    private List<Orderdetail> orderdetail;

    //省略get和set方法
}
         <!-- 一對多查詢: -->
	  <resultMap type="com.zwp.po.Orders" id="OrdersAndOrderdetailResultMap" extends="OrdersUserResultMap">
	 	<!-- 訂單資訊 -->
	 	<!-- 使用者資訊 -->
	 	<!-- extends繼承:可以不用再配置訂單資訊和使用者資訊的對映 -->
	 	
	 	<!-- 訂單明細資訊:
	 	一個訂單關聯查詢出了多條明細,要使用collection進行對映
	 	collection:對關聯查詢多條對映到集合物件中;
	 	property:將關聯查詢多條對映到pojo的哪個屬性中;
	 	ofType:指定對映到list集合屬性中pojo的型別。
	 	 -->
	 	<collection property="orderdetail" ofType="com.zwp.po.Orderdetail">
	 		<id column="orderdetail_id" property="id"/>
	 		<result column="items_id" property="itemsId"/>
	 		<result column="items_num" property="itemsNum"/>
	 		<result column="orders_id" property="ordersId"/>
	 	</collection>
	 </resultMap>
	 
	 <select id="findOrdersAndOrderdetailResultMap" resultMap="OrdersAndOrderdetailResultMap">
		select orders.*,
			user.username,
			user.sex,
			user.address,
			orderdetail.id orderdetail_id,
			orderdetail.items_id,
			orderdetail.items_num,
			orderdetail.orders_id
 		from orders,user,orderdetail
		where orders.user_id=user.id and orderdetail.orders_id=orders.id
	 </select>

小結:mybatis使用resultMap的collection對關聯查詢的多條記錄對映到一個list集合屬性中。

如果使用resultType實現:將訂單明細對映到orders中的ordertails中,需要自己處理,使用雙重迴圈遍歷,去掉重複記錄,將訂單明細放在ordertails中。

(3)多對多查詢:

對映思路:將使用者資訊對映到user中。

在user類中新增訂單列表屬性List<Orders>orderslist,將使用者建立的訂單對映到orderlist;

在Orders中新增訂單明細列表屬性List<OrderDetail>orderdetails,將訂單的明細對映到orderdetails;

在OrderDetail中新增items屬性,將訂單明細所對應的商品對映到items。

	 <!-- 多對多查詢 -->
	 <resultMap type="com.zwp.po.User" id="UserAndItemsResultMap">
	 	<!-- 配置使用者資訊 -->
	 	<id column="user_id" property="id"/>
	 	<result column="username" property="username"/>
	 	<result column="sex" property="sex"/>
	 	<result column="address" property="address"/>
	 	<!-- 配置訂單資訊:使用者對訂單:一對多關係:collection -->
	 	<collection property="orders" ofType="com.zwp.po.Orders">
	 		<id column="id" property="id" />
		 	<result column="user_id" property="userId" />
		 	<result column="number" property="number" />
		 	<result column="createtime" property="createtime" />
		 	<result column="note" property="note" />
		 	<!-- 配置訂單詳情資訊:訂單對訂單詳情:一對多關係:collection -->
		 	<collection property="orderdetail" ofType="com.zwp.po.Orderdetail">
				<id column="orderdetail_id" property="id"/>
		 		<result column="items_id" property="itemsId"/>
		 		<result column="items_num" property="itemsNum"/>
		 		<result column="orders_id" property="ordersId"/>
		 		<!-- 配置商品資訊:訂單詳情對商品:一對一:association -->
		 		<association property="items" javaType="com.zwp.po.Items">
		 			<id column="itemsid" property="id"/>
			 		<result column="name" property="name"/>
			 		<result column="price" property="price"/>
			 		<result column="detail" property="detail"/>
			 		<result column="items_creatime" property="creatime"/>
		 		</association>
		 	</collection>
	 	</collection>
	 </resultMap>
	
	 <select id="findUserAndItemsResultMap" resultMap="UserAndItemsResultMap">
		select orders.*,
			user.username,
			user.sex,
			user.address,
			orderdetail.id orderdetail_id,
			orderdetail.items_id,
			orderdetail.items_num,
			orderdetail.orders_id,
			items.id itemsid,
			items.name,
			items.price,
			items.detail,
			items.creatime items_creatime
		from orders,user,orderdetail,items
		where orders.user_id=user.id and orderdetail.orders_id=orders.id and items_id=items.id
	 </select>
public class User {
    private Integer id;
    private String username;
    private String birthday;
    private String sex;
    private String address;
    
    private List<Orders> orders;
}
public class Orders {
    private Integer id;
    private Integer userId;
    private String number;
    private Date createtime;
    private String note;
    
    private User user;
 
    private List<Orderdetail> orderdetail;
}
public class Orderdetail {
    private Integer id;
    private Integer ordersId;
    private Integer itemsId;
    private Integer itemsNum;
    
    private Items items;
}
public class Items {
    private Integer id;
    private String name;
    private Float price;
    private String pic;
    private Date creatime;
    private String detail;
}

(4)總結:

①resultMap:使用association和collection完成一對一和一對多高階對映,用於對結果有特殊的對映要求。

②association:

    作用:將關聯查詢資訊對映到一個pojo物件中。

    場合:為了方便查詢關聯資訊,可以使用association將關聯訂單資訊對映為使用者物件的pojo屬性中,比如:查詢訂單及關聯使用者資訊。

    使用resultType無法將查詢結果對映到pojo物件的pojo屬性中,根據對結果集查詢遍歷的需要選擇使用resultType還是resultMap。

③collection:

    作用:將關聯查詢資訊對映到一個list集合中。

    場合:為了方便查詢遍歷關聯資訊可以使用collection,將關聯資訊對映到list集合中,比如:查詢使用者許可權範圍模組下及模組下的選單,可以使用collection將其許可權模組對映到許可權模組list中,將選單列表對映到許可權模組物件的選單list屬性中,這樣做的目的也是方便對查詢結果進行遍歷查詢。

    如果使用resultType無法將查詢結果對映到List集合中。

9、延時載入:

resultMap的association和collection具備延時載入功能。

延時載入:先從單表查詢,需要時再從關聯表去關聯查詢,大大提高資料庫效能,因為查詢單表要比關聯查詢多表速度要快。

(1)使用association中的select指定延遲載入去執行的statement的id

	<!-- 延遲載入:
		查詢使用者訂單資訊:使用者資訊要求延遲載入 -->
	<resultMap type="com.zwp.po.Orders" id="OrderUserLazyLoading">
		<id column="id" property="id" />
	 	<result column="user_id" property="userId" />
	 	<result column="number" property="number" />
	 	<result column="createtime" property="createtime" />
	 	<result column="note" property="note" />
	 	
	 	<!-- select:表示需要延時載入的statement的id,如果不在同一個namespace,需要加上namespace
	 		column:表示關聯的欄位-->
	 	<association property="user" javaType="com.zwp.po.User" select="findUserById" column="user_id">
	 		<id column="user_id" property="id" />
		 	<result column="username" property="username" />
		 	<result column="sex" property="sex" />
		 	<result column="address" property="address" />
		 	<result column="birthday" property="birthday" />
	 	</association>
	</resultMap>	
		
	<!-- 不可以使用resultType,因為resultType沒有延遲載入功能 -->
	<select id="findOrderUserLazyLoading" resultMap="OrderUserLazyLoading">
		select * from orders
	</select>
	
	<!-- 查詢訂單關聯查詢使用者,使用者資訊需要延時載入 -->
	<select id="findUserById" parameterType="int" resultType="com.zwp.po.User">
		SELECT * FROM USER WHERE id=#{id}
	</select>

(2)延遲載入配置:

Mybatis預設沒有開啟延時載入,需要在SqlMapperConfig.xml中的setting配置。

	<!-- settings:配置全域性變數 -->
	<settings>
		<!-- 開啟延遲載入開關 -->
		<setting name="lazyLoadingEnabled" value="true"/>
		<!-- 將積極載入改為消極載入,即按需載入 -->
		<setting name="aggressiveLazyLoading" value="false"/>
	</settings>

(3)總結:

使用延時載入方法,先去查詢簡單的sql(最好是單表,也可以關聯查詢),再去按需要載入關聯查詢的其他資訊。

10、一級快取:(mybatis預設支援一級快取)

快取:提高系統的效能,減少資料庫的壓力。



11、二級快取:(預設不開啟)


(1)開啟二級快取:

①在核心配置檔案SqlMapConfig.xml中加入:

	<!-- settings:配置全域性變數 -->
	<settings>
		<!-- 開啟二級快取 -->
		<setting name="cacheEnabled" value="true"/>
	</settings>

②在xxxMapper.xml檔案中開啟二級快取,xxxMapper.xml下的sql執行完會儲存到他的快取區域(HashMap)

<mapper namespace="com.zwp.mapper.OrdersMapperCustom">
	<!-- 開啟本mapper下的二級快取
	<cache/>
</mapper>	

(2)useCache配置:禁用二級快取:

在statement中設定useCache=false可以禁用當前select語句的二級快取,即每次查詢都會發出sql去查詢,預設是true,即改sql使用二級快取。

<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">

場景:針對每次查詢都需要更新的資料sql,要設定成useCache=false,禁用二級快取。

(3)重新整理快取(清空快取):

設定statement配置中的flushCache="true"屬性,預設情況下為true即重新整理快取,如果改成false則不會重新整理。

<insert id="insertUser" parameterType="com.zwp.domain.User" flushCache="true">

場景:一般情況下執行完commit操作都需要重新整理快取,flushCache=true表示重新整理快取,這樣可以避免資料庫髒讀。

12、分佈快取:mybatis整合ehcache:

分佈快取:可以實現對快取資料進行集中管理。

(1)Mybatis無法實現分散式快取,需要和其他分散式快取框架進行整合。

(2)整合方法:

        mybatis提供了一個cache介面,如果要實現自己的快取邏輯,實現cache介面開發即可。

       mybatis和ehcache整合,mybatis和ehcache整合包中提供了一個Cache介面的實現類。



(3)加入jar包依賴:


(4)整合ehcache:


<mapper namespace="com.zwp.mapper.OrdersMapperCustom">
	<!-- 開啟本mapper下的二級快取
	type:指定cache介面的實現的型別,mybatis預設使用PerpetualCache-->
	<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

(5)加入ehcache的配置檔案:

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="D:\develop\ehcache" />
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache> 

13、mybatis和spring整合開發:

需要spring通過單例方式管理SqlSessionFactory。

spring和mybatis整合生成代理物件,使用SqlSessionFactory建立SqlSession,持久層的mapper都需要由spring進行管理。

步驟:

(1)匯入jar包依賴:

(2)sqlSessionFactory配置:

在applicationContext.xml配置sqlSessionFatory,sqlSessionFatory在mybatis和spring的整合包下。

<?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"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/tx
		http://www.springframework.org/schema/tx/spring-tx.xsd">
		
	<!-- 1.載入資料庫配置檔案 -->
	<context:property-placeholder location="classpath:db.properties"/>
		
	<!-- 2.配置連線池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
		<property name="driverClass" value="${jdbc.driver}"></property>
		<property name="jdbcUrl" value="${jdbc.url}"></property>
		<property name="user" value="${jdbc.username}"></property>
		<property name="password" value="${jdbc.password}"></property>
	</bean>

	<!-- 3.建立會話工廠sqlSessionFactory -->		
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- 載入mybatis的配置檔案 -->
		<property name="configLocation" value="mybatis/SqlMapConfig.xml"></property>
		<!-- 配置資料來源 -->
		<property name="dataSource" ref="dataSource"></property>
	</bean>
</beans>
		

(3)①原始dao開發:

--User.xml檔案:

<mapper namespace="test">
	<select id="findUserById" parameterType="int" resultType="com.zwp.ssm.po.User">
		SELECT * FROM USER WHERE id=#{id}
	</select>	 
</mapper>

在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>
	<!-- 載入對映檔案 -->
	<mappers>
		<!-- 通過resource載入單個對映檔案 -->
		<mapper resource="sqlmap/User.xml"></mapper>
	</mappers>
</configuration>
--Dao:(實現類繼承SqlSessionDaoSupport
public interface UserDao {
	//根據id查詢使用者
        public User findUserById(int id) throws Exception;
}

DaoImpl介面實現類需要注入sqlSessionFactory,通過spring進行注入:

public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao{
	//繼承SqlSessionDaoSupport
	//父類已經定義SqlSessionFactory物件和set方法,不需要重新寫
	@Override
	public User findUserById(int id) throws Exception{
		
		SqlSession sqlSession=this.getSqlSession();//不需要手動關閉sqlSession
		System.out.println(sqlSession);
		User user=sqlSession.selectOne("test.findUserById",id);
		return user;
	}
}

通過spring建立介面的bean物件:

	<!--原始dao介面 -->
	<bean id="userDao" class="com.zwp.Dao.UserDaoImpl">
		<!-- sqlSessionFactory不能寫錯 -->
		<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
	</bean>
(3)②mapper代理開發:

--mapper.xml和mapper.java:


public interface UserMapper {
	/*
	(1)mapper.java介面中方法名和mapper.xml中的statement的id一致
	(2)mapper.java介面中方法的輸入引數型別和mapper.xml中statement的parameterType指定的型別一致
	(3)mapper.java介面中方法的返回值型別和mapper.xml中statement的resultment中resultType指定型別一致。
	 */
	
	//根據id查詢使用者
	public User findUserById(int id) throws IOException;
}
<?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="com.zwp.ssm.mapper.UserMapper">
	<select id="findUserById" parameterType="int" resultType="com.zwp.ssm.po.User">
		SELECT * FROM USER WHERE id=#{id}
	</select>	
</mapper>

----通過mapperFactoryBean建立代理物件(此方法存在問題):

<!-- mapper介面 -->
	<!-- MapperFactoryBean:根據mapper介面生成代理物件 -->
	<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
		<!-- mapperInterface指定mapper介面 -->
		<property name="mapperInterface" value="com.zwp.ssm.mapper.UserMapper"></property>
		<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
	</bean>

此方法的問題:如果有很多個mapper,需要針對每個mapper進行單獨配置。

解決方法:通過MapperScannerConfigure進行mapper批量掃描。

	<!-- mapper批量掃描,從mapper包中掃描出mapper,自動建立代理物件並且在spring容器中註冊
	遵循規範:需要mapper介面類名和mapper.xml對映檔名稱一致,且在同一目錄下 
	自動掃描出來的mapper的bean的id為類名(首字母小寫)-->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<!-- 指定掃描的包名 -->
		<!-- 如果掃描多個包,每個包中間使用半形逗號隔開 -->
		<property name="basePackage" value="com.zwp.ssm.mapper"></property>
		<!-- sqlSessionFactoryBeanName不能寫成sqlSessionFactory,不然會導致連線不上資料庫 -->
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
	</bean>

相關推薦

no