Mybatis(3、延遲載入、查詢快取、與ehcache整合、逆向工程、與spring整合)
版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/www1056481167/article/details/70597788
延遲載入
延遲載入:先從單表查詢、需要時再從關聯表去關聯查詢,大大提高 資料庫效能,因為查詢單表要比關聯查詢多張錶速度要快。
使用association實現延遲載入
需要先定義連個mapper的方法對應的statements。
1、只查詢訂單資訊
在查詢訂單的statement中使用association去延遲載入(執行)下邊的statement(關聯查詢使用者資訊)
<!-- 查詢訂單關聯使用者,使用者資訊需要延遲載入 -->
<select id="findOrdersUserLazyLoading" resultMap="OrdersUserLazyLoadingResultMap">
SELECT * FROM orders
</select>
2、關聯查詢使用者資訊
通過上邊查詢到的訂單資訊中user_id去關聯查詢使用者資訊
使用UserMapper.xml中的findUserById
<select id="findUserById" parameterType="int" resultType="user">
SELECT * FROM USER WHERE id=#{value}
</select>
上邊先去執行findOrdersUserLazyLoading,當需要去查詢使用者的時候先去查詢findUserBuyId,通過resultMap的定義將延遲載入執行配置起來。
延遲載入resultMap
使用association中的select指定延遲載入去執行的statement中的id
<!-- 延遲載入的resultMap -->
<resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserLazyLoadingResultMap">
<!--對訂單資訊進行對映配置 -->
<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(是根據user_id查詢使用者資訊的statement)
要使用userMapper.xml中findUserById完成根據使用者id(user_id)使用者資訊的查詢,
如果findUserById不在本mapper中需要前邊加namespace
column:訂單資訊中關聯使用者資訊查詢的列,是user_id
關聯查詢的sql理解為:
SELECT
orders.*, (
SELECT
username
FROM
USER
WHERE
orders.user_id = USER .id
) username,
(
SELECT
sex
FROM
USER
WHERE
orders.user_id = USER .id
) sex
FROM
orders
-->
<association property="user" javaType="cn.itcast.mybatis.po.User"
select="cn.itcast.mybatis.mapper.UserMapper.findUserById" column="user_id">
<!-- 實現對使用者資訊進行延遲載入 -->
</association>
</resultMap>
Mapper.java
// 查詢訂單關聯查詢使用者,使用者資訊是延遲載入
public List<Orders> findOrdersUserLazyLoading() throws Exception;
測試
1、執行上邊mapper方法(findOrdersUserLazyLoading),內部去呼叫cn.itcast.mybatis.mapper.OrdersMapperCustom中的findOrdersUserLazyLoading只查詢orders資訊(單表)。
2、在程式中去遍歷上一步驟查詢出的List<Orders>,當我們呼叫Orders中的getUser方法時,開始進行延遲載入。
3、延遲載入,去呼叫UserMapper.xml中findUserbyId這個方法獲取使用者資訊。
延遲載入的配置
mybatis預設沒有開啟延遲載入,需要在SqlMapConfig.xml中setting配置。
在mybatis核心配置檔案中配置:
lazyLoadingEnabled、aggressiveLazyLoading
mybatis.xml的配置
<settings>
<!-- 開啟延遲載入 的開關 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 將積極載入改為消極載入即按需要載入 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
查詢快取
一級快取
mybatis提供查詢快取,用於減輕資料壓力,提高資料庫效能。
mybaits提供一級快取,和二級快取。
一級快取是SqlSession級別的快取。在操作資料庫時需要構造 sqlSession物件,在物件中有一個數據結構(HashMap)用於儲存快取資料。不同的sqlSession之間的快取資料區域(HashMap)是互相不影響的。
二級快取是mapper級別的快取,多個SqlSession去操作同一個Mapper的sql語句,多個SqlSession可以共用二級快取,二級快取是跨SqlSession的。
為什麼要用快取?
如果快取中有資料就不用從資料庫中獲取,大大提高系統性能。
工作原理:
一級快取的測試
@Test
public void testCache1() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();//建立代理物件
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//下邊查詢使用一個SqlSession
//第一次發起請求,查詢id為1的使用者
User user1 = userMapper.findUserById(1);
System.out.println(user1);
// 如果sqlSession去執行commit操作(執行插入、更新、刪除),清空SqlSession中的一級快取,這樣做的目的為了讓快取中儲存的是最新的資訊,避免髒讀。
//更新user1的資訊
user1.setUsername("測試使用者22");
userMapper.updateUser(user1);
//執行commit操作去清空快取
sqlSession.commit();
//第二次發起請求,查詢id為1的使用者
User user2 = userMapper.findUserById(1);
System.out.println(user2);
sqlSession.close();
}
應用:
正式開發,是將mybatis和spring進行整合開發,事務控制在service中。
一個service方法中包括很多mapper方法呼叫。
service{
//開始執行時,開啟事務,建立SqlSession物件
//第一次呼叫mapper的方法findUserById(1)
//第二次呼叫mapper的方法findUserById(1),從一級快取中取資料
//方法結束,sqlSession關閉
}
如果是執行兩次service呼叫查詢相同的使用者資訊,不走一級快取,因為session方法結束,sqlSession就關閉,一級快取就清空。
二級快取
原理:
首先開啟mybatis的二級快取。
sqlSession1去查詢使用者id為1的使用者資訊,查詢到使用者資訊會將查詢資料儲存到二級快取中。
如果SqlSession3去執行相同 mapper下sql,執行commit提交,清空該 mapper下的二級快取區域的資料。
sqlSession2去查詢使用者id為1的使用者資訊,去快取中找是否存在資料,如果存在直接從快取中取出資料。
二級快取與一級快取區別,二級快取的範圍更大,多個sqlSession可以共享一個UserMapper的二級快取區域。
UserMapper有一個二級快取區域(按namespace分) ,其它mapper也有自己的二級快取區域(按namespace分)。
每一個namespace的mapper都有一個二快取區域,兩個mapper的namespace如果相同,這兩個mapper執行sql查詢到資料將存在相同 的二級快取區域中。
開啟二級快取
mybaits的二級快取是mapper範圍級別,除了在SqlMapConfig.xml設定二級快取的總開關,還要在具體的mapper.xml中開啟二級快取。
1、在核心配置檔案SqlMapConfig.xml中加入
<!-- 開啟二級快取 -->
<setting name="cacheEnabled" value="true"/>
</settings>
2、在UserMapper.xml中開啟二級快取,UserMapper.xml下的sql執行完成會儲存到它的快取區域(hashMap)
<mapper namespace="test">
<!—開啟本namespace的二級快取-->
<cache/>
呼叫pojo實現序列化介面
public class User implements Serializable {
//屬性名和資料庫表的欄位對應
private int id;
private String username;// 使用者姓名
private String sex;// 性別
private Date birthday;// 生日
private String address;// 地址
為了將快取資料提取出執行反序列化操作,因為二級快取資料儲存介質多種多樣,不一樣的記憶體。
測試方法
// 二級快取測試
@Test
public void testCache2() throws Exception {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
// 建立代理物件
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
// 第一次發起請求,查詢id為1的使用者
User user1 = userMapper1.findUserById(1);
System.out.println(user1);
//這裡執行關閉操作,將sqlsession中的資料寫到二級快取區域
sqlSession1.close();
//使用sqlSession3執行commit()操作
UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
User user = userMapper3.findUserById(1);
user.setUsername("張明明");
userMapper3.updateUser(user);
//執行提交,清空UserMapper下邊的二級快取
sqlSession3.commit();
sqlSession3.close();
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
// 第二次發起請求,查詢id為1的使用者
User user2 = userMapper2.findUserById(1);
System.out.println(user2);
sqlSession2.close();
}
useCache配置
在statement中設定useCache=false可以禁用當前select語句的二級快取,即每次查詢都會發出sql去查詢,預設情況是true,即該sql使用二級快取。
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
總結:針對每次查詢都需要最新的資料sql,要設定成useCache=false,禁用二級快取。
重新整理快取
在mapper的同一個namespace中,如果有其它insert、update、delete操作資料後需要重新整理快取,如果不執行重新整理快取會出現髒讀。
設定statement配置中的flushCache="true" 屬性,預設情況下為true即重新整理快取,如果改成false則不會重新整理。使用快取時如果手動修改資料庫表中的查詢資料會出現髒讀。
如下:
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">
總結:一般下執行完commit操作都需要重新整理快取,flushCache=true表示重新整理快取,這樣可以避免資料庫髒讀。
mybatis整合ehcache
依賴jar
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.0.0</version>
</dependency>
ehcache:是一個分散式的快取框架
目的:為了提高系統併發,效能、一般對系統進行分散式部署(叢集部署方式)。
分散式方法
mybatis提供了一個cache介面,如果要實現自己的快取邏輯,實現cache介面開發即可。
mybatis和ehcache整合,mybatis和ehcache整合包中提供了一個cache介面的實現類。
mybatis預設實現cache類
整合ehcache
配置mapper中cache中的type為ehcache對cache介面的實現類。
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
<!-- 開啟mapper的namespace下的二級快取
type:指定cache介面的實現類的型別,mybatis預設使用PerpetualCache要和ehcache整合,
需要配置type為ehcache實現cache介面型別
-->
<cache type="cn.itcast.mybatis.util.PerpetualCache"/>
加入ehcache配置檔案
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="F:\develop\ehcache" />
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
spring和mybatis整合
在applicationContext.xml配置sqlSessionFactory和資料來源。
<!-- 載入配置檔案 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 資料來源,使用dbcp -->
<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}" />
<property name="maxActive" value="10" />
<property name="maxIdle" value="5" />
</bean>
<!-- sqlSessinFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 載入mybatis的配置檔案 -->
<property name="configLocation" value="mybatis/SqlMapConfig.xml" />
<!-- 資料來源 -->
<property name="dataSource" ref="dataSource" />
</bean>
原始dao開發
dao介面
public interface UserDao {
// 根據id查詢使用者資訊
public User findUserById(int id) throws Exception;
}
實現類
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
@Override
public User findUserById(int id) throws Exception {
//繼承SqlSessionDaoSupport,通過this.getSqlSession()得到sqlSessoin
SqlSession sqlSession = this.getSqlSession();
User user = sqlSession.selectOne("test.findUserById", id);
return user;
}
}
dao配置
<!-- 原始dao介面 -->
<bean id="userDao" class="cn.itcast.ssm.dao.UserDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
測試程式碼
public class UserDaoImplTest {
private ApplicationContext applicationContext;
//在setUp這個方法得到spring容器
@Before
public void setUp() throws Exception {
applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml");
}
@Test
public void testFindUserById() throws Exception {
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
//呼叫userDao的方法
User user = userDao.findUserById(1);
System.out.println(user);
}
}
mapper代理開發
mapper.xml和mapper.java
通過MapperScannerConfigurer進行掃描(建議使用)
<!-- mapper批量掃描,從mapper包中掃描出mapper介面,自動建立代理物件並且在spring容器中註冊
遵循規範:將mapper.java和mapper.xml對映檔名稱保持一致,且在一個目錄 中
自動掃描出來的mapper的bean的id為mapper類名(首字母小寫)
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 指定掃描的包名
如果掃描多個包,每個包中間使用半形逗號分隔
-->
<property name="basePackage" value="cn.itcast.ssm.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
測試程式碼
@Test
public void testFindUserById() throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"classpath:spring/applicationContext.xml");
UserMapper userMapper = (UserMapper) applicationContext
.getBean("userMapper");
User user = userMapper.findUserById(1);
System.out.println(user);
}
逆向工程
下載依賴
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
配置檔案:
修改generatorConfig.xml的配置資訊
主要修改的內容有:
1、jdbcConnection的資料庫連線資訊。
2、sqlMapGenerator的targetPackage,mapper.xml對映檔案生成存放的位置
3、table將需要生成的表的表名都配置到配置檔案中
<?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>
<!--資料庫連線的資訊:驅動類、連線地址、使用者名稱、密碼 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root"
password="mysql">
</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" />
<!-- 從資料庫返回的值被清理前後的空格 -->
<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>
<!-- 指定資料庫表**需要配置**-->
<table tableName="items"></table>
</context>
</generatorConfiguration>
執行生成的程式
@Test
public void aa() throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
callback, warnings);
myBatisGenerator.generate(null);
}
生成後的程式碼
---------------------
作者:Koma-forever
來源:CSDN
原文:https://blog.csdn.net/www1056481167/article/details/70597788
版權宣告:本文為博主原創文章,轉載請附上博文連結!