转载

关于 JPA 连表查询和 redis 序列化遇到的小问题

一、JPA

1. 连表查询时数据长度正常,内容都是重复的,MySQL 数据库运行查询语句结果正常

先看写法:

package cn.bridgeli.demo.repository;

import cn.bridgeli.demo.entity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

/**
 * @author BridgeLi
 */
public interface E1Repository extends JpaRepository<E1, Integer> {
    @Query(value = "SELECT t1.id, t1.name, t2.score FROM t1 LEFT JOIN t2 ON t1.id = t2.t1_id LIMIT ?1, ?2", nativeQuery = true)
    List<E1> queryE1s(Integer pageNum, Integer pageSize);
}

package cn.bridgeli.demo.entity;

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Transient;

/**
 * @author BridgeLi
 */
@Data
@Entity
public class E1 {
    @Id
    private Integer id;
    private String name;
    @Transient
    private String course;
    private Integer score;
}

整体大概就是有两张表 t1 和 t2,一对多的关系,t1 的主键是 t2 的外键,执行的截图我就不做了,问题呢,大概就是上面描述的那样,有一个连表查询的需求,JPA 做的,返回给前端的数据,返回长度是对的,但是内容都是重复的,当时第一次看到这个问题的时候,怀疑是 SQL 的问题,然后就把

原因:JPA 映射 entity 时,是根据 id 来居分不同实体的,id 相同,则认为是同一条记录,会重复记录,而不会分别记录其它字段不同的值

解决方案:知道了原因就很容易解决了,只需要一对多,不要用一的那张表做主键用多的那张表做主键就好了。

2. 查询的时候列不存在

这个不是我遇到过,之前听某个同事说,用 JPA 查询的时候,报某个列不存在,而他没有写要查询这个列,当时忙其他的事没有在意,后面也没有关注和测试,个人猜测可以用我上面写的 @Transient 标签来解决。@Transient 表示该属性并非一个到数据库表的字段的映射,忽略该属性。如果一个属性并非数据库表的字段映射,就务必将其标示为 @Transient,否则默认其注解为 @Basic。

2. Redis 时不时的会报一个错:java.lang.String cannot be cast to java.lang.Long,代码如下:

public String getSerialNumber() {
        ValueOperations<String, Long> operations = redisTemplate.opsForValue();
        String today = DateTime.now().toString(DateTimeFormat.forPattern("yyyyMMdd"));

        Long serial = Long.valueOf(new StringBuffer(today).append("001").toString());
        Boolean result = operations.setIfAbsent(today, serial);
        if (!result) {
            serial = operations.increment(today, 1);
            redisTemplate.expire(today, 1, TimeUnit.DAYS);
        }
        return serial.toString();
    }

然后定位了一下,就是 Redis 序列化的时候报的错,看一下序列化的方式吧:

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="connectionFactory"/>

        <property name="keySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
        </property>
        <property name="valueSerializer" ref="jackson2JsonRedisSerializer"/>

        <property name="hashKeySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
        </property>
        <property name="hashValueSerializer" ref="jackson2JsonRedisSerializer"/>
    </bean>

    <bean id="jackson2JsonRedisSerializer"
          class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer">
    </bean>

没发现有什么问题啊,当时应急就出现了重启一下解决,为什么想到重启一下解决呢,因为上线的时候测试了一下没有问题的,所以想着重启一下是不是就好了,试了一下还真解决了,所以就这么干了两次,差点怀疑是不是 spring-data-redis 有 bug,其实不可能的,不是说 spring-data-redis 不可能有 bug,而是这么小的概率,这么严重的 bug,怎么可能别人都遇不到就我们遇到了,而且网上还没人说?后面闲的时候想这个问题不应该啊,重启解决也不是事,还是得从根本上解决,所以就看了一下代码,搜了一下序列化的地方,这么一查还真遇到了,在另一个地方,有个同事不知道咋回事写了个这玩意:

redisTemplate.setKeySerializer(new StringRedisSerializer());
    redisTemplate.setValueSerializer(new StringRedisSerializer());

也就是在那个地方修改了序列化方式,当这个地方被执行了一次之后,序列化方式就被修改了,所以启动的时候配置的序列化方式就不行了,然后再次执行的就报错了,找到原因,然后就好解决了,问同事为什么这个地方修改序列化方式,有什么原因吗?不改行不行,同事:在网上抄的这段代码,不知道为什么,不改应该也可以,遂删除完事,经测试无误,后面再未出现。

总结:其实今天写的三个问题,都是非常小的问题,原因也都很简单,相关的程序员对自己使用的框架不熟,然后瞎写出错,这个就要求我们第一步模仿别人写没有问题,毕竟要快速完成功能,但是写完之后一定要测试,写的对不对,对其他地方有没有影响,完成功能之后,能不能看一下文档或者资料,看看自己写的这段代码啥意思,为什么这么写,这么写会不会有什么没发现的问题,这样才能提高自己,而不是写完完事,哪管后面洪水滔天。

原文  https://www.bridgeli.cn/archives/668
正文到此结束
Loading...