【面試之持久化框架】hibernate、mybatis、jpa規範
1.hibernate 和 mybatis 的區別
·實現上的區別:mybatis只有一個核心jar包,另外和spring整合需要mybatis-spring的jar包,使用快取需要mybatis-ehcache的jar包,而hibernate需要一系列的jar包,這也側面反映了mybatis相對小巧,簡單,而hibernate相對來說比較強大,複雜;mybatis的配置主要包括一個用於對映各種類的xml檔案以及和實體類一一對應的對映檔案,hibernate包括hibernate.cfg.xml和實體類的配置檔案hibernate.hbm.xml。
·hibernate屬於全自動的ORM框架,著力點在於POJO和資料庫表之間的對映,完成對映即可自動生成和執行sql;而mybatis相對來說屬於半自動的ORM框架,著力點在於POJO和SQL之間的對映,自己編寫sql語句,然後通過配置檔案將所需的引數和返回的欄位對映到POJO。如果說hibernate屬於ORM Mapping,那麼mybatis相當於SQL Mapping.
·從上面的描述也可以看出,hibernate整合的專案比mybatis整合的專案更容易移植,因為hibernate使用的HQL語句與具體的資料庫無關,而mybatis編寫的sql語句都是和資料庫相關聯的,可移植性差。
·hibernate擁有自己的日誌統計slf4j,而mybatis自身不帶有日誌記錄。
·快取方面,都可以使用第三方的快取。hibernate有一級快取和二級快取之分,一級快取屬於session級別的快取,需要對session的生命週期進行管理,二級快取屬於sessionFactory級別的快取;mybatis雖然也有一級快取,但是和spring整合使用時每次都是重新開啟一個session進行操作,所以是無法使用,當然可以開啟二級快取,被所有sqlsessiong共享。
·mybatis需要手動寫sql語句,這既是好的一面也是不好的一面,與hibernate相比好的一面在於可以高度優化sql語句以提升系統性能;不好的一面在於工作量相對比較大;如果牽扯到資料庫的修改,則mybatis相對於hibernate的修改量更大
·學習成本上,hibernate相對來說,週期比較長。
第三方快取 ehcache配置:
micro(比較全的配置)<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="false" monitoring="autodetect" dynamicConfig="true"> <!-- Sets the path to the directory where cache .data files are created. If the path is a Java System Property it is replaced by its value in the running VM. The following properties are translated: user.home - User's home directory user.dir - User's current working directory java.io.tmpdir - Default temp file path --> <diskStore path="java.io.tmpdir"/> <!--Default Cache configuration. These will applied to caches programmatically created through the CacheManager. The following attributes are required for defaultCache: maxInMemory - Sets the maximum number of objects that will be created in memory eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the element is never expired. timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used if the element is not eternal. Idle time is now - last accessed time timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used if the element is not eternal. TTL is now - creation time overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache has reached the maxInMemory limit. --> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" /> <!--Predefined caches. Add your cache configuration settings here. If you do not have a configuration for your cache a WARNING will be issued when the CacheManager starts The following attributes are required for defaultCache: name - Sets the name of the cache. This is used to identify the cache. It must be unique. maxInMemory - Sets the maximum number of objects that will be created in memory eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the element is never expired. timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used if the element is not eternal. Idle time is now - last accessed time timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used if the element is not eternal. TTL is now - creation time overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache has reached the maxInMemory limit. --> <!-- Sample cache named sampleCache1 This cache contains a maximum in memory of 10000 elements, and will expire an element if it is idle for more than 5 minutes and lives for more than 10 minutes. If there are more than 10000 elements it will overflow to the disk cache, which in this configuration will go to wherever java.io.tmp is defined on your system. On a standard Linux system this will be /tmp" //秒--> <cache name="parameterCache" maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="0" timeToLiveSeconds="300" overflowToDisk="false" diskPersistent="false" memoryStoreEvictionPolicy="LRU" /> <!-- Sample cache named sampleCache2 This cache contains 1000 elements. Elements will always be held in memory. They are not expired. --> <!-- <cache name="sampleCache2" maxElementsInMemory="1000" eternal="true" timeToIdleSeconds="0" timeToLiveSeconds="0" overflowToDisk="false" /> --> <!-- Place configuration for your caches following --> </ehcache>
<defaultCache
maxElementsInMemory="10000"
maxElementsOnDisk="100000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
<cache
name="com.raipeng.micro.core.module.common.entity.ConfigEntity"
maxElementsInMemory="10000"
maxElementsOnDisk="100000"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
eternal="true"
overflowToDisk="true"
diskSpoolBufferSizeMB="50"
/>
mybatis的一些配置
mybatisconfig.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>
<package name="com.*.sales.entity"/>
</typeAliases>
<mappers>
<mapper resource="com/*/sales/front/repository/mybatis/sales.xml"/>
<mapper resource="com/*/sales/front/repository/mybatis/saleOrder.xml"/>
<mapper resource="com/*/sales/front/repository/mybatis/distributorAccount.xml"/>
<mapper resource="com/*/sales/front/repository/mybatis/snsUser.xml"/>
<mapper resource="com/*/sales/front/repository/mybatis/rechargeOrder.xml"/>
<mapper resource="com/*/sales/front/repository/mybatis/poster.xml"/>
<mapper resource="com/*/sales/front/repository/mybatis/withdrawRecord.xml"/>
<mapper resource="com/*/sales/front/repository/mybatis/flowProduct.xml"/>
</mappers>
</configuration>
其中一個pojo
<?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.*.sales.entity.DistributorAccount">
<resultMap id="distributorAccountResultMap" type="distributorAccount">
<id property="id" column="id"></id>
<result property="operatorId" column="operator_id"></result>
<result property="orderNo" column="orderno"></result>
<result property="price" column="price"></result>
<result property="mobile" column="mobile"></result>
<result property="flowPackage" column="flow_package"></result>
<result property="operatorType" column="operator_type"></result>
<result property="status" column="status"></result>
<result property="createdDate" column="created_date"></result>
<result property="finishDate" column="finish_date"></result>
<result property="lastModified" column="last_modified"></result>
<result property="remark" column="remark"></result>
<result property="sellerId" column="seller_id"></result>
<result property="version" column="version"></result>
<result property="refundOperatorId" column="refund_operator_id"></result>
</resultMap>
<select id="selectDistributorAccountList" parameterType="distributorAccountForm" resultMap="distributorAccountResultMap">
select o.* from rp_app_account o
<where>
o.seller_id = #{operatorId}
<if test="beginDateStr != null and beginDateStr != ''">
AND DATE_FORMAT(o.last_modified,'%Y-%m-%d') >= str_to_date(#{beginDateStr},'%Y-%m-%d')
</if>
<!--%Y-%m-%d %H:%i:%s-->
<if test="endDateStr != null and endDateStr != ''">
<![CDATA[
and DATE_FORMAT(o.last_modified,'%Y-%m-%d') <= str_to_date(#{endDateStr},'%Y-%m-%d')
]]>
</if>
<if test="operatorType != null and operatorType != ''">
and o.operator_type = #{operatorType}
</if>
</where>
order by o.last_modified desc
limit #{offset},#{pageSize}
</select>
<insert id="saveDistributorAccount" >
insert into rp_app_account (operator_id,orderno,price,mobile,flow_package,operator_type,status,created_date,finish_date,last_modified,remark,seller_id,version)
values (#{operatorId},#{orderNo},#{price},#{mobile},#{flowPackage},#{operatorType},#{status},now(),#{finishDate},now(),#{remark},#{sellerId},#{version})
</insert>
<update id="updateStatusByOrderNo" >
update rp_app_account set status = #{status} ,last_modified = now(),refund_operator_id = #{refundOperatorId} where orderno = #{orderNo}
</update>
</mapper>
DaoImpl繼承該抽象類即可使用sqlsession
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.annotation.Autowired;
/**
*
* @author
*
*/
public abstract class AbstractMyBatisBaseRepository extends
SqlSessionDaoSupport {
@Autowired
public final void init(SqlSessionTemplate sessionTemplate) {
this.setSqlSessionTemplate(sessionTemplate);
}
}
和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:p="http://www.springframework.org/schema/p" 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/aop http://www.springframework.org/schema/aop/spring-aop-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/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:sysconfig.properties" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" p:driverClassName="${jdbc.mysql.driverClassName}"
p:url="${jdbc.mysql.url}" p:username="${jdbc.mysql.username}"
p:password="${jdbc.mysql.password}" p:maxActive="100000" p:maxIdle="10"
p:testOnBorrow="true" p:validationQuery="select 1" >
<description>開發環境本地庫配置</description>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:dataSource-ref="dataSource" p:configLocation="classpath:mybatisconfig.xml" />
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource" />
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="update*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="mod*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="save*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="find*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="load*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="query*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="export*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="modify*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="cancle*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="logout*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="*" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- 通過AOP實現橫向切入 -->
<aop:config>
<aop:advisor pointcut="execution(* com.raipeng.sales.*.service.*.*(..))" advice-ref="txAdvice" />
</aop:config>
</beans>
配置cache
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<context:component-scan base-package="com.raipeng.sales" />
<tx:annotation-driven />
<cache:annotation-driven cache-manager="cacheManager" />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"
p:cacheManager-ref="ehcache" />
<!-- Ehcache library setup -->
<bean id="ehcache"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:configLocation="classpath:ehcache.xml" />
</beans>
都匯入到spring配置檔案中,用importjpa的配置檔案persistenceContext.xml,hibernate實現
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
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/util http://www.springframework.org/schema/util/spring-util-4.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<jpa:repositories base-package="com.raipeng.micro.core.module.**.dao" />
<jpa:auditing/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"
p:jndiName="java:comp/env/jdbc/microDB"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource"
p:packagesToScan="com.raipeng.micro.core.module.**.entity"
p:jpaVendorAdapter-ref="jpaVendorAdapter"
p:jpaProperties-ref="jpaProperties"/>
<util:properties id="jpaProperties">
<prop key="hibernate.show_sql">${config.hibernate.show.sql}</prop>
<prop key="hibernate.format_sql">${config.hibernate.show.sql}</prop>
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="javax.persistence.validation.mode">none</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.SingletonEhCacheRegionFactory</prop>
<prop key="hibernate.cache.provider_configuration">ehcache.xml</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="javax.persistence.sharedCache.mode">ENABLE_SELECTIVE</prop>
</util:properties>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
</beans>
spring配置檔案中
<import resource="classpath*:persistenceContext.xml"/>