springmvc+双数据源+redis+thymeleaf+spring-data-jpa

因为闲来无事在工作中写了个小项目,先看配置:
springmvc+双数据源+redis+thymeleaf+spring-data-jpa

配置文件采用携程的apollo自动注入。

1. mvc使用权自动配置,由springboot完成自动配置,具体的请求路径由requestmapping设置。

2. 双数据源

2.1 设置数据源

springmvc+双数据源+redis+thymeleaf+spring-data-jpa

 上图设置了一个DataSourceProperties,至于为什么设置另一个Properties,是因为apollo下来的密码是密文,有一个密钥,这个密钥的key在DataSourceProperties中没有这样的key值,且DataSourceProperties不能单独取值或者设置值,因此只能再生成一个备用Properties。另外DataSourceProperties需要加上@Primary注解,以便让Springboot放弃自己配置此Bean,而是使用我们配置的这个Bean。还有Properties的Bean的名字设置为2222,也是为了区分Springboot自己设置的Properties。

springmvc+双数据源+redis+thymeleaf+spring-data-jpa

 上面设置了两个数据源,这两个数据源属于除了用户名其他都是相同的,注意第一个因为加了@Primary注解,所以可以不用写bean的名字,后面再给data-jpa的EntityManagerFactory Bean注入数据源的时候,默认是注入加了@Primary注解的主数据源,而第二个数据源因为是备用数据源,因此需要加上名字,以便在给备用EntityManagerFactory Bean设置数据源的时候可以按照名字注入。可以看到Properties主要是为了取用户名然后设置到DataSourceProperties中,还有密码。

2.2 设置EntityManagerFactory

springmvc+双数据源+redis+thymeleaf+spring-data-jpa

 设置双数据源很简单,无论是mybatis或者spring-data-jpa,或者是其他的都是一样的,mybatis是设置不同的sqlSessionFactory,Spring-data-jpa设置EntityManagerFactory。

注意第二个注解是关键,它是告诉Springboot按照手动操作来完成此次生成EntityManagerFactory Bean的流程。第一个参数告诉Spring由哪个管理器工厂类进行数据库Dao接口的生成,第二个参数指定了扫描的具体仓库包范围。另外这里注入DataSource只需要@AutoWired即可,因为主数据源会被自动化注入。

springmvc+双数据源+redis+thymeleaf+spring-data-jpa

 第二个和第一个大同小异,区别是注入数据源的时候需要额外加上@Qualifier按照名字注入数据源。

3. redis

springmvc+双数据源+redis+thymeleaf+spring-data-jpa

 就是比较简单的配置了一个,没什么特殊的,记得配置序列化器,在开始的时候,因为误以为Springboot会自动帮我配置序列化器,但是由于我没有指定RedisTemplate的泛型,导致Springboot不知道给我设置了个啥序列化器,然后就怎么也获取不到redis的数据,但是也不报错,然后就痛苦的找了一天的问题,因为redis数据源连接是成功的,获取删除数据也不报错,配置都没有问题,哇简直痛苦,然后看到了一篇文章,我大概明白了可能是由于错误序的列化器导致数据乱码无法正确获取到数据。

4. thymeleaf

这个属于半前端框架,可以让后端开发触摸到前端开发的乐趣,我很喜欢这玩意,由于是简单的使用,所以所有的配置操作都交给SpringBoot做了,所有的设置按照默认配置设置,目录结构是这样的

springmvc+双数据源+redis+thymeleaf+spring-data-jpa

一个简单的页面内容如下:

springmvc+双数据源+redis+thymeleaf+spring-data-jpa

thymeleaf为了减轻学习的成本,他的基本上所有语法都是在html语法前面加上 th: ,然后就可以完成thymeleaf的注入,这个th: 表签的作用是当对象数据被获取到后会替换掉本身html中设置的值,如果为空就啥也不做,因此即使没有后台数据传入,thymeleaf也可以被html正确的解析, 注意在页面头加上下面的声明,否则th: 语法不会被识别:

springmvc+双数据源+redis+thymeleaf+spring-data-jpa

static放置静态文件,templates放置html页面以及其他服务器资源文件,但是不建议把其他文件放在这个目录下,这个目录下的文件只能通过内部服务获取,即Controller才有权限获取,这是thymeleaf的规定。js,css等资源放在static即可。

5. data-jpa

Spring-Data是Spring针对数据库范围设置的顶层接口,下辖接口实现类可以操作sql,nosql等所有数据库,野心勃勃的Spring。而关系型数据库的实现类是spring-data-jpa,操作redis除了redisTemplate还可以使用spring-data-redis,然后就可以写接口,实现crudRepository接口,就可以按照接口操作redis。具体的配置参考上面的双数据源设置。

springmvc+双数据源+redis+thymeleaf+spring-data-jpa

 上面是一个简单的按照名字的分页功能实现,我觉得jpa这种接口的形式写sql,挺带感的,既可以脱离平台,又可以减少人为sql的失误,我觉得比mybatis的事事亲为,要好的多,当然个人意见。

以上就是全部内容。

*希望你我都可以绽放自己*

---------------------------------------

关于jpa双数据源的事务管理,因为是首次将jpa引入项目,所以激动之余在写更新语句的时候加事务注解后,没有注意到这是一个双数据源,然后更新语句一直报错,最后定位到下面的地方:

springmvc+双数据源+redis+thymeleaf+spring-data-jpa

 因为physicalTransactionDelegate为空导致,这个更新sql一直失败,并报下面的错误:

springmvc+双数据源+redis+thymeleaf+spring-data-jpa

 然后我一直在纠结为什么事务是空的,然后这个错误的点就一直误导我,百度上搜索怎么也找不到正确的回到,试了各种方法翻来覆去都一直是这个问题,搞了我两天,然后周末的早上再去看个问题的时候,还是报这个错误,忽然我想到为什么事务是空的,这么简单的问题不应该这么复杂,然后我又重新检查了一遍配置文件,忽然发现了我配置的是双数据源,然后就去百度搜索jpa配置双数据源,果然发现我根本没有按照要求配置第二个数据源的事务管理器,那么我的@Transaction注解其实只是得到了主数据源的事务管理器,所以第二个数据源的事务管理器自然是空的。  jpa2.1配置多个数据源和事务及Executing an update/delete query异常处理_飞龙的博客-CSDN博客

然后分别配置了各自的事务管理器,结果完美解决问题。

--------------------------------------------

        关于jpa联合主键的问题,jpa对于联合主键的表除了要加多个@Id注解外,还需要加@IdClass注解。最关键的是如果存在联合主键,而没有按照要求在实体类上加上联合主键标志,即多个@Id注解,那么未加@Id注解的主键字段的模糊查询将会失效,并且返回重复的字段,我猜测是jpa内部对从数据库中的查询到的数据又增加了自己的过滤处理,因为工作原因,自己的代码不便贴出,就举个栗子说明以下:

       假如表A有一个联合主键,分别是字段a和字段b,但实际上由于自己的疏忽或者其他因素,在实体类中只对字段a添加了一个@Id主键索引标志,那么jpa就会认为这张表的主键只有一个那就是字段a,所以你对字段a和字段b都进行模糊查询的数据,jpa会再过滤一波,将a字段相同的后续数据直接复制一份,这样你得到的数据其实是对a模糊查询的数据,并进行了加上b模糊查询的数量的复制。

       就是jpa把后续b模糊查询到的数据认为这是重复的数据,然后它又不把这些重复删除而是将a的数据又复制了一边。因此如果表中存在联合主键,切记在实体类中也要做出相应的注解表明。

--------------------------------------------

      Spring-Data有pageAndSort*接口,因此可以方便进行分页处理,但是整合redis的时候希望通过实现此接口来进行分页处理,恐怕不妙。因为spring-data-redis针对redis只是做了hash数据类型的处理,就是@RedisHash注解,这个注解会和@Id注解的字段组合成hash类型的key,所以其他的redis数据类型,采用这种接口型的方式是无法处理的。只能通过redisTemplate处理。