- 浏览: 238654 次
- 性别:
- 来自: 宁波
文章分类
最新评论
-
endual:
想要查询这样channel,其子栏目 channels 数列里 ...
spring-data-jpa 复杂查询的写法(包含or的查询) -
fanglei613:
LZ的头像是国見比呂顺便问一下 html2canvas是异步请 ...
html2canvas 截屏后上传到服务器端(springmvc3) -
yonghong:
sping3.1.2下测试,rest异常捕获不到,没有返回js ...
springmvc下,web服务(restful)异常 和非web服务异常 的统一处理 -
yannanying:
你好,我想问一下,为什么像xml等配置文件也会有这个东西,它会 ...
archetype:create-from-project生成项目的包名 -
leobluewing:
小丑皇吃巧克力 写道请问 图片黑色遮罩是怎么回事 啊?应该是h ...
html2canvas 截屏后上传到服务器端(springmvc3)
本文所有测试用代码在https://github.com/wwlleo0730/restjplat 的分支addDB上
目前在使用spring-data-jpa和hibernate4的时候,对于缓存关系不是很清楚,以及二级缓存和查询缓存的各种配置等等,于是就有了这篇初级的jpa+hibernate缓存配置使用的文章。
JPA和hibernate的缓存关系,以及系统demo环境说明
JPA全称是:Java Persistence API
所以,JPA只是一系列定义好的持久化操作的接口,在系统中使用时,需要真正的实现者,在这里,我们使用Hibernate作为实现者。所以,还是用spring-data-jpa+hibernate4+spring3.2来做demo例子说明本文。
JPA规范中定义了很多的缓存类型:一级缓存,二级缓存,对象缓存,数据缓存,等等一系列概念,搞的人糊里糊涂,具体见这里:
http://en.wikibooks.org/wiki/Java_Persistence/Caching
不过缓存也必须要有实现,因为使用的是hibernate,所以基本只讨论hibernate提供的缓存实现。
很多其他的JPA实现者,比如toplink(EclipseLink),也许还有其他的各种缓存实现,在此就不说了。
先直接给出所有的demo例子
hibernate实现中只有三种缓存类型:
一级缓存,二级缓存和查询缓存。
在hibernate的实现概念里,他把什么集合缓存之类的统一放到二级缓存里去了。
1. 一级缓存测试:
文件配置:
可见没有添加任何配置项。
由此可见:同一个session内部,一级缓存生效,同一个id的对象只有一个。不同session,一级缓存无效。
2. 二级缓存测试:
文件配置:
1:实体类直接打上 javax.persistence.Cacheable 标记。
2:配置文件修改,在 jpaProperties 下添加,用ehcache来实现二级缓存,另外因为加入了二级缓存,我们将hibernate的统计打开来看看到底是不是被缓存了。
注1:如果在配置文件中加入了
<prop key="javax.persistence.sharedCache.mode">ENABLE_SELECTIVE</prop>,则不需要在实体内配置hibernate的 @cache标记,只要打上JPA的@cacheable标记即可默认开启该实体的2级缓存。
注2:如果不使用javax.persistence.sharedCache.mode配置,直接在实体内打@cache标记也可以。
至于 hibernate的 hibernate.cache.use_second_level_cache这个属性,文档里是这么写的:
即打上只要有@cache标记,自动开启。
所以有两种方法配置开启二级缓存:
第一种不使用hibernate的@cache标记,直接用@cacheable标记和缓存映射配置项。
第二种用hibernate的@cache标记使用。
另外javax.persistence.sharedCache.mode的其他配置如下:
The javax.persistence.sharedCache.mode property can be set to one of the following values:
测试代码:
输出:
可见二级缓存生效了,只输出了一条sql语句,同时监控中也出现了数据。
另外也可以看看如果是配置成ALL,并且把@cacheable删掉,输出如下:
并且可以看见,所有的实体类都加入二级缓存中去了
3. 查询缓存测试:
一,二级缓存都是根据对象id来查找,如果需要加载一个List的时候,就需要用到查询缓存。
在Spring-data-jpa实现中,也可以使用查询缓存。
文件配置:
在 jpaProperties 下添加,这里必须明确标出增加查询缓存。
然后需要在方法内打上@QueryHint来实现查询缓存,我们写几个方法来测试如下:
测试方法:
输出结果:
很明显,查询缓存生效。但是为什么第一种方法查询缓存无法生效,原因不明,只能后面看看源代码了。
4.集合缓存测试:
根据hibernate文档的写法,这个应该是算在2级缓存里面。
测试类:
测试方法:
输出:
在统计数据里可见二级缓存的对象数量。
本文我们不讨论关于缓存的更新策略,脏数据等等的东西,只是讲解配置方式。
接下来是源代码篇
理清楚各种配置以后,我们来看一下hibernate和spring-data-jpa的一些缓存实现源代码。
上面有个遗留问题,为什么spring-data-jpa默认实现的findAll()方法无法保存到查询缓存?只能啃源代码了。
打断点跟踪吧
入口方法是spring-data-jpa里的 SimpleJpaRepository类
果然有个cacheable,值为false,说明的确是没有从缓存里取数据。
用自定义的jpa查询方法测试后发现,这个值为true。
于是接着看cacheable的取值过程:
factory.getSettings().isQueryCacheEnabled() 这个一定是true,因为是在配置文件中打开的。那只能是queryParameters.isCacheable() 这个的问题了。
接下来query的建立过程:
也就是说spring-data-jpa接口提供的简单快速的各种接口实现全是不能使用查询缓存的,完全不知道为什么这么设计。
接下来看看我们自己实现的查询方法实现:
直接找到query方法的setCacheable()方法打断点,因为肯定改变这个值才能有查询缓存。
在返回query的过程中通过applyHints()方法读取了方法上的QueryHint注解从而设置了查询缓存。
https://github.com/wwlleo0730/restjplat/tree/addDB/
目前在使用spring-data-jpa和hibernate4的时候,对于缓存关系不是很清楚,以及二级缓存和查询缓存的各种配置等等,于是就有了这篇初级的jpa+hibernate缓存配置使用的文章。
JPA和hibernate的缓存关系,以及系统demo环境说明
JPA全称是:Java Persistence API
引用
JPA itself is just a specification, not a product; it cannot perform persistence or anything else by itself.
JPA仅仅只是一个规范,而不是产品;使用JPA本身是不能做到持久化的。
JPA仅仅只是一个规范,而不是产品;使用JPA本身是不能做到持久化的。
所以,JPA只是一系列定义好的持久化操作的接口,在系统中使用时,需要真正的实现者,在这里,我们使用Hibernate作为实现者。所以,还是用spring-data-jpa+hibernate4+spring3.2来做demo例子说明本文。
JPA规范中定义了很多的缓存类型:一级缓存,二级缓存,对象缓存,数据缓存,等等一系列概念,搞的人糊里糊涂,具体见这里:
http://en.wikibooks.org/wiki/Java_Persistence/Caching
不过缓存也必须要有实现,因为使用的是hibernate,所以基本只讨论hibernate提供的缓存实现。
很多其他的JPA实现者,比如toplink(EclipseLink),也许还有其他的各种缓存实现,在此就不说了。
先直接给出所有的demo例子
hibernate实现中只有三种缓存类型:
一级缓存,二级缓存和查询缓存。
在hibernate的实现概念里,他把什么集合缓存之类的统一放到二级缓存里去了。
1. 一级缓存测试:
文件配置:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" /> <property name="packagesToScan" value="com.restjplat.quickweb" /> <property name="jpaProperties"> <props> <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> <prop key="hibernate.format_sql">true</prop> </props> </property> </bean>
可见没有添加任何配置项。
private void firstCacheTest(){ EntityManager em = emf.createEntityManager(); Dict d1 = em.find(Dict.class, 1); //find id为1的对象 Dict d2 = em.find(Dict.class, 1); //find id为1的对象 logger.info((d1==d2)+""); //true EntityManager em1 = emf.createEntityManager(); Dict d3 = em1.find(Dict.class, 1); //find id为1的对象 EntityManager em2 = emf.createEntityManager(); Dict d4 = em2.find(Dict.class, 1); //find id为1的对象 logger.info((d3==d4)+""); //false }
输出为:因为sql语句打出来太长,所以用*号代替 Hibernate: *********** 2014-03-17 20:41:44,819 INFO [main] (DictTest.java:76) - true Hibernate: *********** Hibernate: *********** 2014-03-17 20:41:44,869 INFO [main] (DictTest.java:84) - false
由此可见:同一个session内部,一级缓存生效,同一个id的对象只有一个。不同session,一级缓存无效。
2. 二级缓存测试:
文件配置:
1:实体类直接打上 javax.persistence.Cacheable 标记。
@Entity @Table(name ="dict") @Cacheable public class Dict extends IdEntity{}
2:配置文件修改,在 jpaProperties 下添加,用ehcache来实现二级缓存,另外因为加入了二级缓存,我们将hibernate的统计打开来看看到底是不是被缓存了。
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop> <prop key="javax.persistence.sharedCache.mode">ENABLE_SELECTIVE</prop> <prop key="hibernate.generate_statistics">true</prop>
注1:如果在配置文件中加入了
<prop key="javax.persistence.sharedCache.mode">ENABLE_SELECTIVE</prop>,则不需要在实体内配置hibernate的 @cache标记,只要打上JPA的@cacheable标记即可默认开启该实体的2级缓存。
注2:如果不使用javax.persistence.sharedCache.mode配置,直接在实体内打@cache标记也可以。
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY) public class Dict extends IdEntity{}
至于 hibernate的 hibernate.cache.use_second_level_cache这个属性,文档里是这么写的:
引用
Can be used to completely disable the second level cache, which is enabled by default for classes which specify a <cache> mapping.
即打上只要有@cache标记,自动开启。
所以有两种方法配置开启二级缓存:
第一种不使用hibernate的@cache标记,直接用@cacheable标记和缓存映射配置项。
第二种用hibernate的@cache标记使用。
另外javax.persistence.sharedCache.mode的其他配置如下:
The javax.persistence.sharedCache.mode property can be set to one of the following values:
- ENABLE_SELECTIVE (Default and recommended value): entities are not cached unless explicitly marked as cacheable.
- DISABLE_SELECTIVE: entities are cached unless explicitly marked as not cacheable.
- NONE: no entity are cached even if marked as cacheable. This option can make sense to disable second-level cache altogether.
- ALL: all entities are always cached even if marked as non cacheable. 如果用all的话,连实体上的@cacheable都不用打,直接默认全部开启二级缓存
测试代码:
private void secondCachetest(){ EntityManager em1 = emf.createEntityManager(); Dict d1 = em1.find(Dict.class, 1); //find id为1的对象 logger.info(d1.getName()); em1.close(); EntityManager em2 = emf.createEntityManager(); Dict d2 = em2.find(Dict.class, 1); //find id为1的对象 logger.info(d2.getName()); em2.close(); }
输出:
Hibernate: ************** a a ===================L2====================== com.restjplat.quickweb.model.Dict : 1
可见二级缓存生效了,只输出了一条sql语句,同时监控中也出现了数据。
另外也可以看看如果是配置成ALL,并且把@cacheable删掉,输出如下:
Hibernate: ************ a a ===================L2====================== com.restjplat.quickweb.model.Children : 0 com.restjplat.quickweb.model.Dict : 1 org.hibernate.cache.spi.UpdateTimestampsCache : 0 org.hibernate.cache.internal.StandardQueryCache : 0 com.restjplat.quickweb.model.Parent : 0 =================query cache=================
并且可以看见,所有的实体类都加入二级缓存中去了
3. 查询缓存测试:
一,二级缓存都是根据对象id来查找,如果需要加载一个List的时候,就需要用到查询缓存。
在Spring-data-jpa实现中,也可以使用查询缓存。
文件配置:
在 jpaProperties 下添加,这里必须明确标出增加查询缓存。
<prop key="hibernate.cache.use_query_cache">true</prop>
然后需要在方法内打上@QueryHint来实现查询缓存,我们写几个方法来测试如下:
public interface DictDao extends JpaRepository<Dict, Integer>,JpaSpecificationExecutor<Dict>{ // spring-data-jpa默认继承实现的一些方法,实现类为 // SimpleJpaRepository。 // 该类中的方法不能通过@QueryHint来实现查询缓存。 @QueryHints({ @QueryHint(name = "org.hibernate.cacheable", value ="true") }) List<Dict> findAll(); @Query("from Dict") @QueryHints({ @QueryHint(name = "org.hibernate.cacheable", value ="true") }) List<Dict> findAllCached(); @Query("select t from Dict t where t.name = ?1") @QueryHints({ @QueryHint(name = "org.hibernate.cacheable", value ="true") }) Dict findDictByName(String name); }
测试方法:
private void QueryCacheTest(){ //无效的spring-data-jpa实现的接口方法 //输出两条sql语句 dao.findAll(); dao.findAll(); System.out.println("================test 1 finish======================"); //自己实现的dao方法可以被查询缓存 //输出一条sql语句 dao.findAllCached(); dao.findAllCached(); System.out.println("================test 2 finish======================"); //自己实现的dao方法可以被查询缓存 //输出一条sql语句 dao.findDictByName("a"); dao.findDictByName("a"); System.out.println("================test 3 finish======================"); }
输出结果:
Hibernate: ************** Hibernate: ************** ================test 1 finish====================== Hibernate: *********** ================test 2 finish====================== Hibernate: *********** ================test 3 finish====================== ===================L2====================== com.restjplat.quickweb.model.Dict : 5 org.hibernate.cache.spi.UpdateTimestampsCache : 0 org.hibernate.cache.internal.StandardQueryCache : 2 =================query cache================= select t from Dict t where t.name = ?1 select generatedAlias0 from Dict as generatedAlias0 from Dict
很明显,查询缓存生效。但是为什么第一种方法查询缓存无法生效,原因不明,只能后面看看源代码了。
4.集合缓存测试:
根据hibernate文档的写法,这个应该是算在2级缓存里面。
测试类:
@Entity @Table(name ="parent") @Cacheable public class Parent extends IdEntity { private static final long serialVersionUID = 1L; private String name; private List<Children> clist; public String getName() { return name; } public void setName(String name) { this.name = name; } @OneToMany(fetch = FetchType.EAGER,mappedBy = "parent") @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) public List<Children> getClist() { return clist; } public void setClist(List<Children> clist) { this.clist = clist; } } @Entity @Table(name ="children") @Cacheable public class Children extends IdEntity{ private static final long serialVersionUID = 1L; private String name; private Parent parent; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "parent_id") public Parent getParent() { return parent; } public void setParent(Parent parent) { this.parent = parent; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
测试方法:
private void cellectionCacheTest(){ EntityManager em1 = emf.createEntityManager(); Parent p1 = em1.find(Parent.class, 1); List<Children> c1 = p1.getClist(); em1.close(); System.out.println(p1.getName()+" "); for (Children children : c1) { System.out.print(children.getName()+","); } System.out.println(); EntityManager em2 = emf.createEntityManager(); Parent p2 = em2.find(Parent.class, 1); List<Children> c2 = p2.getClist(); em2.close(); System.out.println(p2.getName()+" "); for (Children children : c2) { System.out.print(children.getName()+","); } System.out.println(); }
输出:
Hibernate: ******************** Michael kate,Jam,Jason,Brain, Michael kate,Jam,Jason,Brain, ===================L2====================== com.restjplat.quickweb.model.Children : 4 com.restjplat.quickweb.model.Dict : 0 org.hibernate.cache.spi.UpdateTimestampsCache : 0 com.restjplat.quickweb.model.Parent.clist : 1 org.hibernate.cache.internal.StandardQueryCache : 0 com.restjplat.quickweb.model.Parent : 1 =================query cache=================
在统计数据里可见二级缓存的对象数量。
本文我们不讨论关于缓存的更新策略,脏数据等等的东西,只是讲解配置方式。
接下来是源代码篇
理清楚各种配置以后,我们来看一下hibernate和spring-data-jpa的一些缓存实现源代码。
上面有个遗留问题,为什么spring-data-jpa默认实现的findAll()方法无法保存到查询缓存?只能啃源代码了。
打断点跟踪吧
入口方法是spring-data-jpa里的 SimpleJpaRepository类
public List<T> findAll() { return getQuery(null, (Sort) null).getResultList(); } 然后到 QueryImpl<X>类的 private List<X> list() { if (getEntityGraphQueryHint() != null) { SessionImplementor sessionImpl = (SessionImplementor) getEntityManager().getSession(); HQLQueryPlan entityGraphQueryPlan = new HQLQueryPlan( getHibernateQuery().getQueryString(), false, sessionImpl.getEnabledFilters(), sessionImpl.getFactory(), getEntityGraphQueryHint() ); // Safe to assume QueryImpl at this point. unwrap( org.hibernate.internal.QueryImpl.class ).setQueryPlan( entityGraphQueryPlan ); } return query.list(); } 进入query.list(); query类的代码解析google一下很多,于是直接到最后: 进入QueryLoader的list方法。 protected List list( final SessionImplementor session, final QueryParameters queryParameters, final Set<Serializable> querySpaces, final Type[] resultTypes) throws HibernateException { final boolean cacheable = factory.getSettings().isQueryCacheEnabled() && queryParameters.isCacheable(); if ( cacheable ) { return listUsingQueryCache( session, queryParameters, querySpaces, resultTypes ); } else { return listIgnoreQueryCache( session, queryParameters ); } }
果然有个cacheable,值为false,说明的确是没有从缓存里取数据。
用自定义的jpa查询方法测试后发现,这个值为true。
于是接着看cacheable的取值过程:
final boolean cacheable = factory.getSettings().isQueryCacheEnabled() && queryParameters.isCacheable();
factory.getSettings().isQueryCacheEnabled() 这个一定是true,因为是在配置文件中打开的。那只能是queryParameters.isCacheable() 这个的问题了。
在query.list()的方法内部: public List list() throws HibernateException { verifyParameters(); Map namedParams = getNamedParams(); before(); try { return getSession().list( expandParameterLists(namedParams), getQueryParameters(namedParams) ); } finally { after(); } } getQueryParameters(namedParams)这个方法实际获取的是query对象的cacheable属性的值,也就是说,query对象新建的时候cacheable的值决定了这个query方法能不能被查询缓存。
接下来query的建立过程:
在 SimpleJpaRepository 类中 return applyLockMode(em.createQuery(query)); 直接由emcreate,再跟踪到 AbstractEntityManagerImpl中 @Override public <T> QueryImpl<T> createQuery( String jpaqlString, Class<T> resultClass, Selection selection, QueryOptions queryOptions) { try { org.hibernate.Query hqlQuery = internalGetSession().createQuery( jpaqlString ); .... return new QueryImpl<T>( hqlQuery, this, queryOptions.getNamedParameterExplicitTypes() ); } catch ( RuntimeException e ) { throw convert( e ); } } 即通过session.createQuery(jpaqlString ) 创建初始化对象。 在query类定义中 public abstract class AbstractQueryImpl implements Query { private boolean cacheable; } cacheable不是对象类型,而是基本类型,所以不赋值的情况下默认为“false”。
也就是说spring-data-jpa接口提供的简单快速的各种接口实现全是不能使用查询缓存的,完全不知道为什么这么设计。
接下来看看我们自己实现的查询方法实现:
直接找到query方法的setCacheable()方法打断点,因为肯定改变这个值才能有查询缓存。
于是跟踪到 SimpleJpaQuery类中 protected Query createQuery(Object[] values) { return applyLockMode(applyHints(doCreateQuery(values), method), method); }
在返回query的过程中通过applyHints()方法读取了方法上的QueryHint注解从而设置了查询缓存。
评论
3 楼
slowvic
2014-09-22
lz,除了spring-data-jpa原生的findAll方法,其他方法,比如最重要的findOne方法,有断点调试过吗?我试了下,用@Cachable注解,貌似确实没效果。
@Cache注解的运行机制是什么呢,为什么这个可以正常缓存?
哈哈,这两个问题调试下就知道的,不过如果lz调过我就省事了。
另外要纠正下,lz自己都说了一、二级缓存的key都是id,findAll方法虽然查询的是list,但也是针对id循环的,所以不是查询缓存而是二级缓存。
@Cache注解的运行机制是什么呢,为什么这个可以正常缓存?
哈哈,这两个问题调试下就知道的,不过如果lz调过我就省事了。
另外要纠正下,lz自己都说了一、二级缓存的key都是id,findAll方法虽然查询的是list,但也是针对id循环的,所以不是查询缓存而是二级缓存。
2 楼
leobluewing
2014-03-21
happyjeef18 写道
你们好。 谢谢分享你的文章。
请问你的说的测试代码 在哪里?https://github.com/wwlleo0730/restjplat 这个上面找不到你说的addDB分支
这个缓存方面的问题也弄的我头痛。 希望你能给个例子 学习学习! 3Q
请问你的说的测试代码 在哪里?https://github.com/wwlleo0730/restjplat 这个上面找不到你说的addDB分支
这个缓存方面的问题也弄的我头痛。 希望你能给个例子 学习学习! 3Q
https://github.com/wwlleo0730/restjplat/tree/addDB/
1 楼
happyjeef18
2014-03-21
你们好。 谢谢分享你的文章。
请问你的说的测试代码 在哪里?https://github.com/wwlleo0730/restjplat 这个上面找不到你说的addDB分支
这个缓存方面的问题也弄的我头痛。 希望你能给个例子 学习学习! 3Q
请问你的说的测试代码 在哪里?https://github.com/wwlleo0730/restjplat 这个上面找不到你说的addDB分支
这个缓存方面的问题也弄的我头痛。 希望你能给个例子 学习学习! 3Q
相关推荐
例子活跃的mq 安卓易于Hibernate4 jpa——spring-data-jpa、hibernate、solr 网状四郎springmvc——spring、springmvc、freemarker、shiro struts2 -- struts2, freemarker, shiro -doc -- 一些资源 -extjs4 -- ...
以Spring Framework为核心容器,Spring data Jpa(Hibernate实现)为数据访问层, Apache Shiro为权限框架,Redis对常用数据进行缓存,前端使用Vue全家桶,前后端分离、JWT鉴权的开源框架。 角色的功能权限控制方式为...
Server端架构: Struts2+ Spring + Spring Data(简化持久层) + JPA接口+ Hibernate(JPA显现) 后台管理系统 页面架构 :jQuery Easyui 框架 前端互联网系统 页面架构 :BootStrap 响应式 + AngularJS Excel解析...
技术选择说明:管理 maven依赖和项目管理 git/svn 版本控制后端 Spring SpringMVC Spring data jpa(hibernate实现) Shiro 验证框架 hibernate validator 缓存 ehcache 数据源 druid servlet 3.0+前端 jsp 验证码 ...
员工SpringMvcRest 使用spring mvc、spring data jpa、ehcache、jsp、javascript和apache tomcat进行员工管理。 描述:它是一个员工管理系统,作为 Web 和休息服务暴露给用户,用户可以使用它执行基本的 crud 操作,...
Jpa(Hibernate实现)为数据访问层, Apache Shiro为权限框架,Redis对常用数据进行缓存,前端使用Vue全家桶,前后端分离、JWT鉴权的开源框架。 角色的功能权限控制方式为基于RBAC规范的Shiro,角色数据范围控制是根据...
Spring MVC Spring Data JPA Hibernate MySQL Spring Data Redis 用于缓存文章 Jade 作为视图模板,我极度不喜欢写 HTML 标签 Bootstrap 没有它我就不会写前端了 这是一个基于 Gradle 的项目,要想...
微航海数据 Micronaut Data是一个数据库访问工具包,它使用Ahead of Time(AoT)... 没有反射或运行时代理-由于完全没有反射缓存,Micronaut Data不使用反射或运行时代理,从而导致更好的性能,更小的堆栈跟踪和更少的
JeeSite是轻量级的,简单易学,本框架以Spring Framework为核心、Spring MVC作为模型视图控制器、Spring Data JPA + Hibernate作为数据库操作层,此组合是Java界业内最经典、最优的搭配组合。前端界面风格采用了结构...
:link: Ligoj靴带 REST +前端模板,带有大量具有许多...Data扩展可实现性能,最少的代码和异常处理基于Spring的前/后架构Spring Boot /安全性/ Web /数据CXF JPA /Hibernate用于JPA和JAX-RS的Hibernate验证器JUnit 5
4.掌握基于Spring整合常用框架并进行项目开发的经验,如:iBatis、Hibernate、Redis、SpringDataJPA 5.熟悉基于JUnit的单元测试,熟悉Dbunit,EasyMock,了解测试驱动编程; 6.web前端技术:熟悉HTML、CSS、JavaScript...
ORM框架:Spring Data JPA、hibernate 4.3.5.Final 日志管理:SLF4J 1.7.21、Log4j 编辑器:ueditor 工具类:Apache Commons、Jackson 2.8.5、POI 3.15 view层:JSP 数据库:mysql、oracle等关系型数据库 前端 dom ...
shiro、hibernate、spring?data?jpa、ehcache等框架,为了统一页面风格使用DWZ作为页面富客户端的展示。 工具 说明 Spring 不用多说了吧,项目粘合剂。 SpringMVC 目前最流行,功能最完备MVC框架。 Spring?Data?Jpa?...
技术选型:Spring Data JPA、Hibernate、Shiro、 Spring MVC、Layer、MySQL 等。 简介: 1、天梯是一款使用Java编写的免费的轻量级CMS系统,目前提供了从后台管理到前端展现的整体解决方案。 2、用户可以不编写一句...
基于SpringBoot,Spring Data JPA,Shiro开发的前后端分离的拥有权限管理的工作系统.具体模块正在开发中..前端 涉及框架 后端框架: 技术 名称 官网 Spring Framework 容器 SpringMVC MVC框架 Spring Data JPA ORM框架...
项目中主要使用了以下技术: Java8的Spring相关的Spring,Spring Mvc,Spring Cloud,spring data jpa,Spring Boot,Hibernate mapstruct主要用于DTO与实体之间的转换flywaydb以版本化的方式管理数据库脚本...
Spring Data JPA的超能力 探索更多JPA和Hibernate 连接池和空中通道 API错误处理和建模 使用Bean验证进行验证 整合测试 API的良好做法和技巧 高级API建模和实施 建模预测,调查和报告 上传和下载文件 交易电子邮件...
- **Spring 相关** Spring, Spring Mvc, Spring Cloud, Spring data jpa, Spring Boot,Hibernate - **mapstruct** 主要用于DTO 与 Entity 之间的转换 - **flywaydb** 以版本化的方式管理数据库脚本 - **thymeleaf** ...
框架:SpringBoot 2.x、Spring Data JPA、Hibernate Validation、Caffeine缓存、SnowFlake ID生成器 日志:Slf4j、Logback 中间件:RabbitMQ、Redis 数据库:demo版采用H2,可自行更换其他主流数据库 接口文档:...
JBoss提供的开源分布缓存式解决方案,能全面支持Spring、Hibernate、JPA、memcache等,并提供了lucence相关的查询接口,高性能WEB框架的必备元素。