解决neo4j @Transactional 与Spring data jpa @Transactional 冲突问题,@CreatedBy,@CreatedDate,@LastModifiedBy,@LastModifiedDate,以及解决@Version失效问题
之前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
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.lzw</groupId>
- <artifactId>web</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <packaging>jar</packaging>
- <name>web</name>
- <description>Demo project for Spring Boot</description>
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.0.0.RELEASE</version>
- <relativePath/> <!-- lookup parent from repository -->
- </parent>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
- <java.version>1.8</java.version>
- <spring-cloud.version>Finchley.M8</spring-cloud.version>
- <skipTests>true</skipTests>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <!--<dependency>-->
- <!--<groupId>org.springframework.cloud</groupId>-->
- <!--<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
- <!--</dependency>-->
- <!--redis-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- </dependency>
- <!-- redis session -->
- <dependency>
- <groupId>org.springframework.session</groupId>
- <artifactId>spring-session-data-redis</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-openfeign</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-security</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-mongodb</artifactId>
- </dependency>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-neo4j</artifactId>
- </dependency>
- <!-- jbatis begin -->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid</artifactId>
- <version>1.1.9</version>
- </dependency>
- <dependency>
- <groupId>org.lzw</groupId>
- <artifactId>jbatis</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>6.0.6</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-jpa</artifactId>
- <version>2.0.0.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- <version>1.3.1</version>
- </dependency>
- <!-- jbatis end -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-dependencies</artifactId>
- <version>${spring-cloud.version}</version>
- <type>pom</type>
- <scope>import</scope>
- </dependency>
- </dependencies>
- </dependencyManagement>
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
- <repositories>
- <repository>
- <id>spring-milestones</id>
- <name>Spring Milestones</name>
- <url>https://repo.spring.io/milestone</url>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- </repository>
- </repositories>
- </project>
首先建立一个抽象类
- /**
- * Created by laizhenwei on 2018/3/21
- */
- @Getter
- @Setter
- @NoArgsConstructor
- @AllArgsConstructor
- @ToString
- @Accessors(chain = true)
- @MappedSuperclass
- public abstract class AbstractJbatisEntity implements Serializable {
- private static final long serialVersionUID = 8413473756947412760L;
- @Id
- @GenericGenerator(name="idGenerator", strategy="uuid") //这个是hibernate的注解/生成32位UUID
- @GeneratedValue(generator="idGenerator")
- private String id;
- }
再建立一个包含@CreatedBy,@CreatedDate,@LastModifiedBy,@LastModifiedDate注解的抽象类 @Version 不写在父类里,并不是每个表都需要乐观锁,哪个表需要,就加在某个pojo里
- /**
- * Created by laizhenwei on 2018/3/21
- */
- @Getter
- @Setter
- @NoArgsConstructor
- @AllArgsConstructor
- @ToString
- @MappedSuperclass
- @Accessors(chain = true)
- @EntityListeners(AuditingEntityListener.class)
- public class AbstractAuditingEntity extends AbstractJbatisEntity {
- @CreatedBy
- private String creator;
- @CreatedDate
- private LocalDateTime createTime;
- @LastModifiedBy
- private String modifier;
- @LastModifiedDate
- private LocalDateTime modifyTime;
- }
实现AuditorAware,监听实体持久化操作,以便从Spring Security 的ContextHolder里面获取当前发起操作的用户信息
- /**
- * Created by laizhenwei on 2018/3/21
- */
- public class SpringSecurityAuditorAware implements AuditorAware<String> {
- public Optional<String> getCurrentAuditor() {
- Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
- if (authentication == null || !authentication.isAuthenticated()|| SecurityUtils.isAnonymous())
- return Optional.of(SecurityUtils.ANONYMOUSUSER);
- return Optional.ofNullable(((UserInfo) authentication.getPrincipal()).getUsername());
- }
- }
配置类这里之所以注释掉@EnableTransactionManagement,是因为在Neo4j配置类里已经存在此注解
- /**
- * Created by laizhenwei on 2018/3/21
- */
- @Configuration
- @EnableJpaAuditing
- @EnableJpaRepositories(basePackages="org.lzw.web.repository.jbatis")
- //@EnableTransactionManagement
- public class JpaConfig{
- @Autowired
- private EntityManagerFactory entityManagerFactory;
- @Bean
- public AuditorAware<String> auditorProvider() {
- return new SpringSecurityAuditorAware();
- }
- @Bean
- public JpaTransactionManager transactionManager(){
- JpaTransactionManager transactionManager = new JpaTransactionManager();
- transactionManager.setEntityManagerFactory(entityManagerFactory);
- return transactionManager;
- }
- }
Neo4j配置类,可见两个TransactionManager Bean 虽然类型不同,但是名字也不能相同,否则注入时会冲突,并且必须有其中一个名字为transactionManager,否则也会报找不到默认的TransactionManager Bean
- /**
- * Created by laizhenwei on 2018/3/21
- */
- @Configuration
- @EnableTransactionManagement
- @EnableNeo4jRepositories(basePackages="org.lzw.web.repository.neo4j")
- public class Neo4jPersistenceContext {
- @Bean
- public SessionFactory getSessionFactory() {
- SessionFactory sessionFactory = new SessionFactory(configuration(),"org.lzw.web.domain.neo4j");
- return sessionFactory;
- }
- @Bean
- public Neo4jTransactionManager neo4jTransactionManager(){
- return new Neo4jTransactionManager(getSessionFactory());
- }
- @Bean
- public org.neo4j.ogm.config.Configuration configuration() {
- return new org.neo4j.ogm.config.Configuration.Builder()
- .connectionLivenessCheckTimeout(50)
- .connectionPoolSize(100)
- .verifyConnection(true)
- // .autoIndex("update")
- .credentials("neo4j","root")
- .uri("bolt://192.168.1.207:7687")
- .build();
- }
- }
- userinfo pojo @Version
- /**
- * Created by laizhenwei on 2018/3/21
- */
- @Entity
- @Table(name = "tenant_user_info")
- @Alias("UserInfo")
- public class UserInfo extends AbstractAuditingEntity implements UserDetails {
- private String username;
- private String password;
- private boolean accountNonExpired;
- private boolean accountNonLocked;
- private boolean credentialsNonExpired;
- private boolean enabled;
- @Version
- private Long version;
- @Transient
- @Override
- public Collection<? extends GrantedAuthority> getAuthorities() {
- return null;
- }
- @Override
- public String getPassword() {
- return this.password;
- }
- @Override
- public String getUsername() {
- return this.username;
- }
- @Override
- public boolean isAccountNonExpired() {
- return this.accountNonExpired;
- }
- @Override
- public boolean isAccountNonLocked() {
- return this.accountNonLocked;
- }
- @Override
- public boolean isCredentialsNonExpired() {
- return this.credentialsNonExpired;
- }
- @Override
- public boolean isEnabled() {
- return this.enabled;
- }
- public UserInfo setUsername(String username) {
- this.username = username;
- return this;
- }
- public UserInfo setPassword(String password) {
- this.password = password;
- return this;
- }
- public UserInfo setAccountNonExpired(boolean accountNonExpired) {
- this.accountNonExpired = accountNonExpired;
- return this;
- }
- public UserInfo setAccountNonLocked(boolean accountNonLocked) {
- this.accountNonLocked = accountNonLocked;
- return this;
- }
- public UserInfo setCredentialsNonExpired(boolean credentialsNonExpired) {
- this.credentialsNonExpired = credentialsNonExpired;
- return this;
- }
- public UserInfo setEnabled(boolean enabled) {
- this.enabled = enabled;
- return this;
- }
- public Long getVersion() {
- return version;
- }
- public void setVersion(Long version) {
- this.version = version;
- }
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof UserInfo))
- return false;
- if (o.toString().equals(this.getUsername()))
- return true;
- return false;
- }
- @Override
- public int hashCode() {
- return this.getUsername().hashCode();
- }
- @Override
- public String toString() {
- return this.getUsername();
- }
- }
- 注解也被增强@Transactional(transactionManager="transactionManager",propagation = Propagation.REQUIRED) ,可以指定transactionManager,来解决多个transactionManager的问题.
@Version 乐观锁,之前再使用Spring data mongo 的时候,感觉很不错.但是开始在Spring data jpa 里面死活无效,version 字段一直为null,百思不得其解,再Spring data jpa 官方文档 居然搜索不到@Version注解,以为被弃用了
后来折腾了很久发现必须使用
- @javax.persistence.Version 可以生效
而使用
- @org.springframework.data.annotation.Version 不生效
- 因为Spring data mongo 就是用Spring的注解,并且认为Spring 都是遵守J2EE 标准的,潜意识觉得用两个注解都可以生效.
后来想想,@Version这乐观锁,是Hibernate实现的,而Hibernate才是Jpa规范的鼻祖,那么如果没有增加对@org.springframework.data.annotation.Version的支持,应该只会认@javax.persistence.Version
测试类,然后去看看是否版本号,以及创建人,创建时间,修改人,修改时间都有了
- @RunWith(SpringRunner.class)
- @SpringBootTest
- public class UserInfoServiceTest {
- @Resource
- private UserInfoService userInfoService;
- @Test
- @Rollback(false)
- @Transactional(transactionManager="transactionManager",propagation = Propagation.REQUIRED)
- public void saveTest(){
- UserInfo userInfo = new UserInfo();
- userInfo.setUsername("athos");
- userInfo.setPassword("1232456");
- userInfo.setEnabled(true);
- userInfo.setCredentialsNonExpired(true);
- userInfo.setAccountNonExpired(true);
- userInfo.setAccountNonLocked(true);
- userInfoService.saveAndFlush(userInfo);
- UserInfo userInfo1 = userInfoService.getOne(userInfo.getId());
- userInfo1.setPassword("123123");
- userInfoService.saveAndFlush(userInfo1);
- }
- }
解决neo4j @Transactional 与Spring data jpa @Transactional 冲突问题,@CreatedBy,@CreatedDate,@LastModifiedBy,@LastModifiedDate,以及解决@Version失效问题的更多相关文章
- 【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 ...
- Spring data jpa JavassistLazyInitializer 不仅是Json序列化问题.以及解决办法
最近偷点时间更新一下框架,使用SpringBoot2.0 整套一起更新一下,发现些小问题 Spring data jpa getOne 返回的是代理对象,延迟加载的,ResponseBody成Json ...
- SpringBoot第九篇:整合Spring Data JPA
作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/10910059.html 版权声明:本文为博主原创文章,转载请附上博文链接! 前言 前面几章, ...
- 快速搭建springmvc+spring data jpa工程
一.前言 这里简单讲述一下如何快速使用springmvc和spring data jpa搭建后台开发工程,并提供了一个简单的demo作为参考. 二.创建maven工程 http://www.cnblo ...
- 深入浅出学Spring Data JPA
第一章:Spring Data JPA入门 Spring Data是什么 Spring Data是一个用于简化数据库访问,并支持云服务的开源框架.其主要目标是使得对数据的访问变得方便快捷,并支持map ...
- Spring Data JPA初使用(转载)
我们都知道Spring是一个非常优秀的JavaEE整合框架,它尽可能的减少我们开发的工作量和难度. 在持久层的业务逻辑方面,Spring开源组织又给我们带来了同样优秀的Spring Data JPA. ...
- Spring Data JPA初使用
我们都知道Spring是一个非常优秀的JavaEE整合框架,它尽可能的减少我们开发的工作量和难度. 在持久层的业务逻辑方面,Spring开源组织又给我们带来了同样优秀的Spring Data JPA. ...
- 干货|一文读懂 Spring Data Jpa!
有很多读者留言希望松哥能好好聊聊 Spring Data Jpa!其实这个话题松哥以前零零散散的介绍过,在我的书里也有介绍过,但是在公众号中还没和大伙聊过,因此本文就和大家来仔细聊聊 Spring D ...
- 【Spring】Spring Data JPA
原始JDBC操作数据库 传统JDBC方式实现数据库操作 package com.imooc.util; import java.io.InputStream; import java.sql.*; i ...
随机推荐
- struts2系列(一):struts2入门(struts2的产生、struts2的工作流程、搭建struts2开发环境)
一. struts2的产生 struts1的缺点: 1. ActionForm过多,而且这个ActionForm在很大程度上又和VO(POJO)重复 ...
- Spring JDBC配置数据源
在本系列教程中,使用的的是MySQL数据库,并创建一个数据库实例:test,在这个数据库实例:test中创建一个表student.如果您使用任何其他数据库,则可以相应地更改DDL和SQL查询,这问题不 ...
- Linq to Entity 动态拼接查询条件(重点是OR)
public static class PredicateExtensions { /// <summary> /// 机关函数应用True时:单个AND有效,多个AND有效:单个OR无效 ...
- ubuntu -- 安装memcached
Memcached的安装依赖libevent.它是memcached所依赖的异步事件通知库,因此在安装memcached之前先要安装libevent. ubuntu安装软件的方法通常有两种 第一种:使 ...
- 使用iftop监控网卡实时流量
Iftop工具主要用来显示本机网络流量情况及各相互通信的流量集合,如单独同哪台机器间的流量大小,非常适合于代理服务器和iptables服务器使用,这样可以方便的查看各客户端流量情况.iftop可以在类 ...
- win10上跑 sqlserver 2000应用程序
将SQL Server 安装程序\X86\SYSTEM\SQLUNIRL.DLL 替换到Win10 的 C:\windows\system32\目录下,64位win10 还要复制到SYSWOW64目录 ...
- CentOS 7 打开关闭FirewallD防火墙端口命令
CentOS 7 使用firewalld代替了原来的iptables,使用方法如下: >>>关闭防火墙 systemctl stop firewalld.service ...
- Mongodb学习笔记(1)--入门
文档 多个键及关联的值有序的放置在一起就是文档,如"greeting":"Hello World!" 特点 文档中键值对是有序的 除了字符串还可以是其他类型:& ...
- 腾讯QQ家族任意支付QB+修改资料csrf
http://jz.qq.com/m_card.shtml POST /cgi-bin/league_change_userinfo HTTP/1.1 Host: jz.qq.com Connecti ...
- 编译并使用带有OpenCL模块的OpenCV for android SDK
OpenCV Android SDK中提供的静态.动态库是不支持OpenCL加速的,如果在程序中调用OpenCL相关函数,编译时不会报错,但运行时logcat会输出如下信息,提示OpenCL函数不可用 ...