之前mybatis特别流行,所以前几个项目都是用@SelectProvider,@InsertProvider,@UpdateProvider,@DeleteProvider 加反射泛型封装了一些通用方法,虽然小伙伴表示使用得比较满意,但是我认为对他们的发展不太好,可以学习一些主流的大厂框架.同时也为把Spring cloud 升级为Finchley.M8,Spring boot 升级为 2.0 ,所以又看了一遍Spring data JPA,之前看了Spring data jpa 觉得 Specification 可读性特别不好,也特别不好理解,就没有深究了,这次再回头看Spring data jpa 加入了一些可以细化控制的锁机制,而且用了Spring data mongo后,也挺喜欢对象持久化监听事件,并且对事务注解的增强(刚好最近使用Neo4J做权限模块,这解决了TransactionManager冲突的问题)

现在想了一下也是愚蠢,我们应该吸收Spring data jpa 优秀的思想,使用Spring data 快速开发,选择性地放弃一些功能,用Mybatis管理长sql,扬长避短,所以整合一了Mybatis + jpa的抽象通用service,怎么封装抽象整合Mybatis,这里就不讲了

mongo版本http://www.cnblogs.com/sweetchildomine/p/7729319.html

完整的pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5.  
  6. <groupId>org.lzw</groupId>
  7. <artifactId>web</artifactId>
  8. <version>0.0.1-SNAPSHOT</version>
  9. <packaging>jar</packaging>
  10. <name>web</name>
  11. <description>Demo project for Spring Boot</description>
  12.  
  13. <parent>
  14. <groupId>org.springframework.boot</groupId>
  15. <artifactId>spring-boot-starter-parent</artifactId>
  16. <version>2.0.0.RELEASE</version>
  17. <relativePath/> <!-- lookup parent from repository -->
  18. </parent>
  19.  
  20. <properties>
  21. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  22. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  23. <java.version>1.8</java.version>
  24. <spring-cloud.version>Finchley.M8</spring-cloud.version>
  25. <skipTests>true</skipTests>
  26. </properties>
  27.  
  28. <dependencies>
  29. <dependency>
  30. <groupId>org.springframework.boot</groupId>
  31. <artifactId>spring-boot-starter-web</artifactId>
  32. </dependency>
  33.  
  34. <!--<dependency>-->
  35. <!--<groupId>org.springframework.cloud</groupId>-->
  36. <!--<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
  37. <!--</dependency>-->
  38.  
  39. <!--redis-->
  40. <dependency>
  41. <groupId>org.springframework.boot</groupId>
  42. <artifactId>spring-boot-starter-data-redis</artifactId>
  43. </dependency>
  44.  
  45. <!-- redis session -->
  46. <dependency>
  47. <groupId>org.springframework.session</groupId>
  48. <artifactId>spring-session-data-redis</artifactId>
  49. </dependency>
  50.  
  51. <dependency>
  52. <groupId>org.springframework.cloud</groupId>
  53. <artifactId>spring-cloud-starter-openfeign</artifactId>
  54. </dependency>
  55.  
  56. <dependency>
  57. <groupId>org.springframework.cloud</groupId>
  58. <artifactId>spring-cloud-starter-security</artifactId>
  59. </dependency>
  60.  
  61. <dependency>
  62. <groupId>org.springframework.boot</groupId>
  63. <artifactId>spring-boot-starter-data-mongodb</artifactId>
  64. </dependency>
  65.  
  66. <dependency>
  67. <groupId>org.projectlombok</groupId>
  68. <artifactId>lombok</artifactId>
  69. <scope>provided</scope>
  70. </dependency>
  71.  
  72. <dependency>
  73. <groupId>org.springframework.boot</groupId>
  74. <artifactId>spring-boot-starter-data-neo4j</artifactId>
  75. </dependency>
  76.  
  77. <!-- jbatis begin -->
  78.  
  79. <dependency>
  80. <groupId>com.alibaba</groupId>
  81. <artifactId>druid</artifactId>
  82. <version>1.1.9</version>
  83. </dependency>
  84.  
  85. <dependency>
  86. <groupId>org.lzw</groupId>
  87. <artifactId>jbatis</artifactId>
  88. <version>1.0-SNAPSHOT</version>
  89. </dependency>
  90.  
  91. <dependency>
  92. <groupId>mysql</groupId>
  93. <artifactId>mysql-connector-java</artifactId>
  94. <version>6.0.6</version>
  95. </dependency>
  96.  
  97. <dependency>
  98. <groupId>org.springframework.boot</groupId>
  99. <artifactId>spring-boot-starter-data-jpa</artifactId>
  100. <version>2.0.0.RELEASE</version>
  101. </dependency>
  102.  
  103. <dependency>
  104. <groupId>org.mybatis.spring.boot</groupId>
  105. <artifactId>mybatis-spring-boot-starter</artifactId>
  106. <version>1.3.1</version>
  107. </dependency>
  108.  
  109. <!-- jbatis end -->
  110.  
  111. <dependency>
  112. <groupId>org.springframework.boot</groupId>
  113. <artifactId>spring-boot-starter-test</artifactId>
  114. <scope>test</scope>
  115. </dependency>
  116.  
  117. </dependencies>
  118.  
  119. <dependencyManagement>
  120. <dependencies>
  121. <dependency>
  122. <groupId>org.springframework.cloud</groupId>
  123. <artifactId>spring-cloud-dependencies</artifactId>
  124. <version>${spring-cloud.version}</version>
  125. <type>pom</type>
  126. <scope>import</scope>
  127. </dependency>
  128. </dependencies>
  129. </dependencyManagement>
  130.  
  131. <build>
  132. <plugins>
  133. <plugin>
  134. <groupId>org.springframework.boot</groupId>
  135. <artifactId>spring-boot-maven-plugin</artifactId>
  136. </plugin>
  137. </plugins>
  138. </build>
  139.  
  140. <repositories>
  141. <repository>
  142. <id>spring-milestones</id>
  143. <name>Spring Milestones</name>
  144. <url>https://repo.spring.io/milestone</url>
  145. <snapshots>
  146. <enabled>false</enabled>
  147. </snapshots>
  148. </repository>
  149. </repositories>
  150.  
  151. </project>

首先建立一个抽象类

  1. /**
  2. * Created by laizhenwei on 2018/3/21
  3. */
  4. @Getter
  5. @Setter
  6. @NoArgsConstructor
  7. @AllArgsConstructor
  8. @ToString
  9. @Accessors(chain = true)
  10. @MappedSuperclass
  11. public abstract class AbstractJbatisEntity implements Serializable {
  12. private static final long serialVersionUID = 8413473756947412760L;
  13.  
  14. @Id
  15. @GenericGenerator(name="idGenerator", strategy="uuid") //这个是hibernate的注解/生成32位UUID
  16. @GeneratedValue(generator="idGenerator")
  17. private String id;
  18.  
  19. }

再建立一个包含@CreatedBy,@CreatedDate,@LastModifiedBy,@LastModifiedDate注解的抽象类 @Version 不写在父类里,并不是每个表都需要乐观锁,哪个表需要,就加在某个pojo里

  1. /**
  2. * Created by laizhenwei on 2018/3/21
  3. */
  4. @Getter
  5. @Setter
  6. @NoArgsConstructor
  7. @AllArgsConstructor
  8. @ToString
  9. @MappedSuperclass
  10. @Accessors(chain = true)
  11. @EntityListeners(AuditingEntityListener.class)
  12. public class AbstractAuditingEntity extends AbstractJbatisEntity {
  13.  
  14. @CreatedBy
  15. private String creator;
  16.  
  17. @CreatedDate
  18. private LocalDateTime createTime;
  19.  
  20. @LastModifiedBy
  21. private String modifier;
  22.  
  23. @LastModifiedDate
  24. private LocalDateTime modifyTime;
  25.  
  26. }

实现AuditorAware,监听实体持久化操作,以便从Spring Security 的ContextHolder里面获取当前发起操作的用户信息

  1. /**
  2. * Created by laizhenwei on 2018/3/21
  3. */
  4. public class SpringSecurityAuditorAware implements AuditorAware<String> {
  5.  
  6. public Optional<String> getCurrentAuditor() {
  7. Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
  8. if (authentication == null || !authentication.isAuthenticated()|| SecurityUtils.isAnonymous())
  9. return Optional.of(SecurityUtils.ANONYMOUSUSER);
  10. return Optional.ofNullable(((UserInfo) authentication.getPrincipal()).getUsername());
  11. }
  12. }

配置类这里之所以注释掉@EnableTransactionManagement,是因为在Neo4j配置类里已经存在此注解

  1.  
  1. /**
  2. * Created by laizhenwei on 2018/3/21
  3. */
  1. @Configuration
  2. @EnableJpaAuditing
  3. @EnableJpaRepositories(basePackages="org.lzw.web.repository.jbatis")
  4. //@EnableTransactionManagement
  5. public class JpaConfig{
  6.  
  7. @Autowired
  8. private EntityManagerFactory entityManagerFactory;
  9.  
  10. @Bean
  11. public AuditorAware<String> auditorProvider() {
  12. return new SpringSecurityAuditorAware();
  13. }
  14.  
  15. @Bean
  16. public JpaTransactionManager transactionManager(){
  17. JpaTransactionManager transactionManager = new JpaTransactionManager();
  18. transactionManager.setEntityManagerFactory(entityManagerFactory);
  19. return transactionManager;
  20. }
  21.  
  22. }

Neo4j配置类,可见两个TransactionManager  Bean 虽然类型不同,但是名字也不能相同,否则注入时会冲突,并且必须有其中一个名字为transactionManager,否则也会报找不到默认的TransactionManager  Bean

  1.  
  1. /**
  2. * Created by laizhenwei on 2018/3/21
  3. */
  1. @Configuration
  2. @EnableTransactionManagement
  3. @EnableNeo4jRepositories(basePackages="org.lzw.web.repository.neo4j")
  4. public class Neo4jPersistenceContext {
  5.  
  6. @Bean
  7. public SessionFactory getSessionFactory() {
  8. SessionFactory sessionFactory = new SessionFactory(configuration(),"org.lzw.web.domain.neo4j");
  9. return sessionFactory;
  10. }
  11.  
  12. @Bean
  13. public Neo4jTransactionManager neo4jTransactionManager(){
  14. return new Neo4jTransactionManager(getSessionFactory());
  15. }
  16.  
  17. @Bean
  18. public org.neo4j.ogm.config.Configuration configuration() {
  19. return new org.neo4j.ogm.config.Configuration.Builder()
  20. .connectionLivenessCheckTimeout(50)
  21. .connectionPoolSize(100)
  22. .verifyConnection(true)
  23. // .autoIndex("update")
  24. .credentials("neo4j","root")
  25. .uri("bolt://192.168.1.207:7687")
  26. .build();
  27. }
  28.  
  29. }
  1. userinfo pojo @Version
  1. /**
  2. * Created by laizhenwei on 2018/3/21
  3. */
  4. @Entity
  5. @Table(name = "tenant_user_info")
  6. @Alias("UserInfo")
  7. public class UserInfo extends AbstractAuditingEntity implements UserDetails {
  8.  
  9. private String username;
  10.  
  11. private String password;
  12.  
  13. private boolean accountNonExpired;
  14.  
  15. private boolean accountNonLocked;
  16.  
  17. private boolean credentialsNonExpired;
  18.  
  19. private boolean enabled;
  20.  
  21. @Version
  22. private Long version;
  23.  
  24. @Transient
  25. @Override
  26. public Collection<? extends GrantedAuthority> getAuthorities() {
  27. return null;
  28. }
  29.  
  30. @Override
  31. public String getPassword() {
  32. return this.password;
  33. }
  34.  
  35. @Override
  36. public String getUsername() {
  37. return this.username;
  38. }
  39.  
  40. @Override
  41. public boolean isAccountNonExpired() {
  42. return this.accountNonExpired;
  43. }
  44.  
  45. @Override
  46. public boolean isAccountNonLocked() {
  47. return this.accountNonLocked;
  48. }
  49.  
  50. @Override
  51. public boolean isCredentialsNonExpired() {
  52. return this.credentialsNonExpired;
  53. }
  54.  
  55. @Override
  56. public boolean isEnabled() {
  57. return this.enabled;
  58. }
  59.  
  60. public UserInfo setUsername(String username) {
  61. this.username = username;
  62. return this;
  63. }
  64.  
  65. public UserInfo setPassword(String password) {
  66. this.password = password;
  67. return this;
  68. }
  69.  
  70. public UserInfo setAccountNonExpired(boolean accountNonExpired) {
  71. this.accountNonExpired = accountNonExpired;
  72. return this;
  73. }
  74.  
  75. public UserInfo setAccountNonLocked(boolean accountNonLocked) {
  76. this.accountNonLocked = accountNonLocked;
  77. return this;
  78. }
  79.  
  80. public UserInfo setCredentialsNonExpired(boolean credentialsNonExpired) {
  81. this.credentialsNonExpired = credentialsNonExpired;
  82. return this;
  83. }
  84.  
  85. public UserInfo setEnabled(boolean enabled) {
  86. this.enabled = enabled;
  87. return this;
  88. }
  89.  
  90. public Long getVersion() {
  91. return version;
  92. }
  93.  
  94. public void setVersion(Long version) {
  95. this.version = version;
  96. }
  97.  
  98. @Override
  99. public boolean equals(Object o) {
  100. if (!(o instanceof UserInfo))
  101. return false;
  102. if (o.toString().equals(this.getUsername()))
  103. return true;
  104. return false;
  105. }
  106.  
  107. @Override
  108. public int hashCode() {
  109. return this.getUsername().hashCode();
  110. }
  111.  
  112. @Override
  113. public String toString() {
  114. return this.getUsername();
  115. }
  116.  
  117. }
  1. 注解也被增强@Transactional(transactionManager="transactionManager",propagation = Propagation.REQUIRED) ,可以指定transactionManager,来解决多个transactionManager的问题.
    @Version 乐观锁,之前再使用Spring data mongo 的时候,感觉很不错.但是开始在Spring data jpa 里面死活无效,version 字段一直为null,百思不得其解,再Spring data jpa 官方文档 居然搜索不到@Version注解,以为被弃用了
    后来折腾了很久发现必须使用
  1. @javax.persistence.Version 可以生效
    而使用
  1. @org.springframework.data.annotation.Version 不生效
  2.  
  3. 因为Spring data mongo 就是用Spring的注解,并且认为Spring 都是遵守J2EE 标准的,潜意识觉得用两个注解都可以生效.
    后来想想,@Version这乐观锁,是Hibernate实现的,而Hibernate才是Jpa规范的鼻祖,那么如果没有增加对@org.springframework.data.annotation.Version的支持,应该只会认@javax.persistence.Version
  1.  
  1.  
  1.  

测试类,然后去看看是否版本号,以及创建人,创建时间,修改人,修改时间都有了

  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest
  3. public class UserInfoServiceTest {
  4.  
  5. @Resource
  6. private UserInfoService userInfoService;
  7.  
  8. @Test
  9. @Rollback(false)
  10. @Transactional(transactionManager="transactionManager",propagation = Propagation.REQUIRED)
  11. public void saveTest(){
  12. UserInfo userInfo = new UserInfo();
  13. userInfo.setUsername("athos");
  14. userInfo.setPassword("1232456");
  15. userInfo.setEnabled(true);
  16. userInfo.setCredentialsNonExpired(true);
  17. userInfo.setAccountNonExpired(true);
  18. userInfo.setAccountNonLocked(true);
  19. userInfoService.saveAndFlush(userInfo);
  20. UserInfo userInfo1 = userInfoService.getOne(userInfo.getId());
  21. userInfo1.setPassword("123123");
  22. userInfoService.saveAndFlush(userInfo1);
  23. }
  24.  
  25. }

解决neo4j @Transactional 与Spring data jpa @Transactional 冲突问题,@CreatedBy,@CreatedDate,@LastModifiedBy,@LastModifiedDate,以及解决@Version失效问题的更多相关文章

  1. 【spring data jpa】使用spring data jpa 的删除操作,需要加注解@Modifying @Transactional 否则报错如下: No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call

    使用spring data jpa 的删除操作,需要加注解@Modifying     @Transactional 否则报错如下: No EntityManager with actual tran ...

  2. Spring data jpa JavassistLazyInitializer 不仅是Json序列化问题.以及解决办法

    最近偷点时间更新一下框架,使用SpringBoot2.0 整套一起更新一下,发现些小问题 Spring data jpa getOne 返回的是代理对象,延迟加载的,ResponseBody成Json ...

  3. SpringBoot第九篇:整合Spring Data JPA

    作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/10910059.html 版权声明:本文为博主原创文章,转载请附上博文链接! 前言   前面几章, ...

  4. 快速搭建springmvc+spring data jpa工程

    一.前言 这里简单讲述一下如何快速使用springmvc和spring data jpa搭建后台开发工程,并提供了一个简单的demo作为参考. 二.创建maven工程 http://www.cnblo ...

  5. 深入浅出学Spring Data JPA

    第一章:Spring Data JPA入门 Spring Data是什么 Spring Data是一个用于简化数据库访问,并支持云服务的开源框架.其主要目标是使得对数据的访问变得方便快捷,并支持map ...

  6. Spring Data JPA初使用(转载)

    我们都知道Spring是一个非常优秀的JavaEE整合框架,它尽可能的减少我们开发的工作量和难度. 在持久层的业务逻辑方面,Spring开源组织又给我们带来了同样优秀的Spring Data JPA. ...

  7. Spring Data JPA初使用

    我们都知道Spring是一个非常优秀的JavaEE整合框架,它尽可能的减少我们开发的工作量和难度. 在持久层的业务逻辑方面,Spring开源组织又给我们带来了同样优秀的Spring Data JPA. ...

  8. 干货|一文读懂 Spring Data Jpa!

    有很多读者留言希望松哥能好好聊聊 Spring Data Jpa!其实这个话题松哥以前零零散散的介绍过,在我的书里也有介绍过,但是在公众号中还没和大伙聊过,因此本文就和大家来仔细聊聊 Spring D ...

  9. 【Spring】Spring Data JPA

    原始JDBC操作数据库 传统JDBC方式实现数据库操作 package com.imooc.util; import java.io.InputStream; import java.sql.*; i ...

随机推荐

  1. struts2系列(一):struts2入门(struts2的产生、struts2的工作流程、搭建struts2开发环境)

    一. struts2的产生 struts1的缺点:                         1. ActionForm过多,而且这个ActionForm在很大程度上又和VO(POJO)重复  ...

  2. Spring JDBC配置数据源

    在本系列教程中,使用的的是MySQL数据库,并创建一个数据库实例:test,在这个数据库实例:test中创建一个表student.如果您使用任何其他数据库,则可以相应地更改DDL和SQL查询,这问题不 ...

  3. Linq to Entity 动态拼接查询条件(重点是OR)

    public static class PredicateExtensions { /// <summary> /// 机关函数应用True时:单个AND有效,多个AND有效:单个OR无效 ...

  4. ubuntu -- 安装memcached

    Memcached的安装依赖libevent.它是memcached所依赖的异步事件通知库,因此在安装memcached之前先要安装libevent. ubuntu安装软件的方法通常有两种 第一种:使 ...

  5. 使用iftop监控网卡实时流量

    Iftop工具主要用来显示本机网络流量情况及各相互通信的流量集合,如单独同哪台机器间的流量大小,非常适合于代理服务器和iptables服务器使用,这样可以方便的查看各客户端流量情况.iftop可以在类 ...

  6. win10上跑 sqlserver 2000应用程序

    将SQL Server 安装程序\X86\SYSTEM\SQLUNIRL.DLL 替换到Win10 的 C:\windows\system32\目录下,64位win10 还要复制到SYSWOW64目录 ...

  7. CentOS 7 打开关闭FirewallD防火墙端口命令

    CentOS 7 使用firewalld代替了原来的iptables,使用方法如下: >>>关闭防火墙 systemctl stop firewalld.service        ...

  8. Mongodb学习笔记(1)--入门

    文档 多个键及关联的值有序的放置在一起就是文档,如"greeting":"Hello World!" 特点 文档中键值对是有序的 除了字符串还可以是其他类型:& ...

  9. 腾讯QQ家族任意支付QB+修改资料csrf

    http://jz.qq.com/m_card.shtml POST /cgi-bin/league_change_userinfo HTTP/1.1 Host: jz.qq.com Connecti ...

  10. 编译并使用带有OpenCL模块的OpenCV for android SDK

    OpenCV Android SDK中提供的静态.动态库是不支持OpenCL加速的,如果在程序中调用OpenCL相关函数,编译时不会报错,但运行时logcat会输出如下信息,提示OpenCL函数不可用 ...