AttributeConverter 在 EclipseLink 中不工作,在 Hibernate 中工作正常

如何解决AttributeConverter 在 EclipseLink 中不工作,在 Hibernate 中工作正常

我想用转换器尝试一个简单的测试用例。不幸的是,它不适用于 payara 5。它适用于 Wildfly 20.0.1。数据库是H2。

pom.xml

<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>fjp</groupId>
    <artifactId>converter</artifactId>
     <version>1.0</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </properties>

    <dependencies>
        <dependency>
            <groupId>jakarta.platform</groupId>
            <artifactId>jakarta.jakartaee-api</artifactId>
            <version>8.0.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>

持久性.xml

    <?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2"
    xmlns="http://xmlns.jcp.org/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
        http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
>
    <persistence-unit name="primary" transaction-type="JTA">
        <!--jta-data-source>java:/TestDS</jta-data-source-->
        <jta-data-source>jdbc/TestDS</jta-data-source>
        <class>fjp.converter.entity.Employee</class>
        <class>fjp.converter.entity.converter.StatusConverter</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
        <properties>
            <property name="javax.persistence.schema-generation.database.action" value="drop-and-create" />
            <property name="eclipselink.logging.level.sql" value="FINE"/>
            <property name="eclipselink.logging.parameters" value="true"/>
             <property name="hibernate.show_sql" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

DAO:

package fjp.converter.dao;    
import java.util.List;   
import fjp.converter.entity.Employee;

public interface EmployeeDAO {
    public Employee find(long i);
    public void create(Employee e);
    public void delete(Employee e);
    public void delete(long i);
    public List<Employee> findByStatus(Employee.Status status);
}

DAOImpl

package fjp.converter.dao;    
import java.util.List;    
import javax.ejb.Stateless;
import javax.persistence.PersistenceContext;
import javax.persistence.EntityManager;
import fjp.converter.entity.Employee;

@Stateless
public class EmployeeDAOImpl implements EmployeeDAO {
    @PersistenceContext
    private EntityManager em;

    public Employee find(long i) {
        return em.find(Employee.class,i);
    }
    @Override
    public void create(Employee e) {
        em.persist(e);
    }
    @Override
    public void delete(long i) {
        var e = this.find(i);
        if(e != null) em.remove(e);
    }
    @Override
    public void delete(Employee e) {
        if(e == null) return;
        delete(e.getId());
    }

    @Override
    public List<Employee> findByStatus(Employee.Status status) {
        return em.createNamedQuery("Employee.findByStatus",Employee.class)
            .setParameter("status",status)
            .getResultList();
    }
}

实体:

package fjp.converter.entity;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.AttributeConverter;
import javax.persistence.Convert;
import javax.persistence.NamedQuery;  
import java.io.Serializable;

@NamedQuery(name="Employee.findByStatus",query="select e from Employee e where e.status=:status")
@Entity
public class Employee implements Serializable{

    public enum Status {
        SENIOR("SENIOR"),JUNIOR("JUNIOR");
        private String code;
        private Status(String s) {
            this.code = s;
        }
        public String getCode() {
            return this.code;
        }
    }

    @Id
    private long id;
    @Convert(converter = fjp.converter.entity.converter.StatusConverter.class)
    private Status status;

    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public Status getStatus() {
        return this.status;
    }
    public void setStatus(Status s) {
        this.status = s;
    }

    @Override
    public String toString() {
        return String.format("id=%d,status=%s",id,status == null ? null : status.getCode());
    }
}

转换器:

package fjp.converter.entity.converter;    
import javax.persistence.Converter;
import javax.persistence.AttributeConverter;    
import fjp.converter.entity.Employee.Status;

@Converter
public class StatusConverter implements AttributeConverter<Status,String> {
    @Override
    public String convertToDatabaseColumn(Status e) {
        return e == null ? null : e.getCode();
    }
    @Override
    public Status convertToEntityAttribute(String s) {
        if(s == null) return null;
        switch(s) {
            case "SENIOR": return Status.SENIOR;
            case "JUNIOR": return Status.JUNIOR;
            default: return null;
        }
    }
}

服务端

package fjp.converter.servlet;    
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServlet;    
import fjp.converter.dao.EmployeeDAO;
import fjp.converter.entity.Employee;
import fjp.converter.entity.Employee.Status;
import javax.inject.Inject;

@WebServlet("/test")
public class Test extends HttpServlet {
    @Inject
    private EmployeeDAO dao;

    @Override
    protected void doGet(HttpServletRequest request,HttpServletResponse response) {
        Employee e = new Employee();
        long id = 1;
        dao.delete(id);
        e.setId(id);
        e.setStatus(Status.SENIOR);
        dao.create(e);

        id = 2;
        dao.delete(id);
        e.setId(id);
        e.setStatus(Status.JUNIOR);
        dao.create(e);

        Status status = Status.SENIOR;
        var list = dao.findByStatus(status);
        for(var o : list) {
            System.out.println(o);
            if(o.getStatus() != status) {
                System.out.println("ERROR !!!!!");
            }
        }
        status = Status.JUNIOR;
        list = dao.findByStatus(status);
        for(var o : list) {
            System.out.println(o);
            if(o.getStatus() != status) {
                System.out.println("ERROR !!!!!");
            }
        }
    }
}

第一次询问 servlet 时,您会收到错误消息:

[2021-05-13T19:08:07.512+0200] [Payara 5.2021.3] [PRÉCIS] [] [org.eclipse.persistence.session./file:/home/frederic/payara5/glassfish/domains/domain1/applications/converter-1.0/WEB-INF/classes/_primary.sql] [tid: _ThreadID=76 _ThreadName=http-thread-pool::http-listener-1(5)] [timeMillis: 1620925687512] [levelValue: 500] [[
  SELECT ID,STATUS FROM EMPLOYEE WHERE (STATUS = ?)
    bind => [SENIOR]]]

[2021-05-13T19:08:07.514+0200] [Payara 5.2021.3] [INFOS] [] [] [tid: _ThreadID=76 _ThreadName=http-thread-pool::http-listener-1(5)] [timeMillis: 1620925687514] [levelValue: 800] [[
  id=2,status=JUNIOR]]

[2021-05-13T19:08:07.514+0200] [Payara 5.2021.3] [INFOS] [] [] [tid: _ThreadID=76 _ThreadName=http-thread-pool::http-listener-1(5)] [timeMillis: 1620925687514] [levelValue: 800] [[
  ERROR !!!!!]]

如果你刷新页面:它会爆炸!

    Local Exception Stack: 
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.7.payara-p3): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.h2.jdbc.JdbcSQLException: Violation dindex unique ou clé primaire: {0}
Unique index or primary key violation: {0}; SQL statement:
INSERT INTO EMPLOYEE (ID,STATUS) VALUES (?,?) [23505-197]

解决方法

问题是您在以 JPA 规范不允许的方式调用对象后正在编辑对象。这里发生的事情是你首先创建 Employee e 并设置它的 ID 和状态(1,SENIOR),然后在这个实例上调用 persist。

然后更改 e (2,JUNIOR) 上的 id 和 status 值,并再次在同一实例上调用 persist 。实例 E 虽然已经被持久化了,所以这被忽略了。当您查询状态 SENIOR 时,EclipseLink 将查询并找到匹配的行 (1,SENIOR),但是当它进入缓存查看是否已经有数据时,它会找到您的 'e' 实例等等只是返回。您的应用程序记录了一个错误,因为您已将 e 的状态更改为 JUNIOR。

为了证明正在发生的事情 - 尝试列出数据库中的内容。

解决方案只是创建第二个 Employee 实例来表示 (2,JUNIOR) 数据。

JPA 提供程序的一些不同之处在于 EclipseLink 将默认维护一级和二级缓存。这会干扰这种情况,因为您正在以 JPA 规范中不允许的方式修改对象,并且 EclipseLink 比没有缓存时记住数据的时间更长。不允许在 JPA 中修改主键。

,

如果我添加到persistence.xml,它会起作用:

<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>

因此您可以重用 Employe,但要注意二级缓存。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-