【问题标题】:Erratic behavior of EntityManagerEntityManager 的异常行为
【发布时间】:2020-05-02 19:36:25
【问题描述】:

长时间浏览器第一次提问。

我的应用程序面临几个问题,我不知道它们是否有共同点,让我感到困惑的是它们不会定期发生或没有模式发生,有时是一个实体有时是另一个,有时以秒分隔的相同请求会产生不同的结果。 问题是:

  1. 当我检索一个实体时,它带有一些属性正确(id)和其他属性 null,所以当我评估实体是否为 null 时它返回 false ,但是当我尝试使用其中一个属性时,它会生成 空指针异常
  2. 当我尝试获取一个关系时它返回 null,我通过获取与查询的关系来解决这个问题,但我不能在任何地方都使用该解决方案
  3. 有时 entityManager 在没有任何解释的情况下关闭,我检查会话是否打开以打开它,但是它评估为 true,但在我尝试执行操作的下一行代码中,它会抛出一个 会话关闭错误
  4. 有时当我保存子实体时,它会在父实体上引发 空指针异常

关于我的实现的说明:

  1. 所有关系都是惰性的
  2. toString 方法中没有任何关系
  3. 我正在使用 CriteriaBuilder 进行查询
  4. 我正在使用 EntityManager 来保存我的实体
  5. 我的一项待处理任务是在同一个事务中保存对多个实体的更改,因此在下面的代码中我提供了这些内容

员工实体

@SuppressWarnings("serial")
@SequenceGenerator(name = "seq_id_employees", sequenceName = "seq_id_employees",
                initialValue = 1, allocationSize = 1)
@Entity
@Table(name = "Employees")
public class Employee implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_id_employees")
    @Column(name = "id")
    private long id;

    @Column(name = "name", nullable = false)
    private String name;
    .
    .
    .    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    @OneToOne(fetch = FetchType.LAZY, mappedBy = "employee")
    private EmployeeDetail empDetails;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "employee")
    private Set<User> users = new HashSet<User>();
    .
    .
    .
    public EmployeeDetail getEmpDetails() {
        return empDetails;
    }

    public void setEmpDetails(EmployeeDetail empDetails) {
        this.empDetails = empDetails;
    }
    .
    .
    .
    @Override
    public String toString() {
        return "EmployeesEntity [id=" + id + ", name=" + name + ", picture=" + Arrays.toString(picture)
                + ", companyMail=" + companyMail + ", active=" + active + ", maxAuth=" + maxAuth + ", created="
                + created + ", updated=" + updated + "]";
    }
}

EmployeeDetail 实体

@SuppressWarnings("serial")
@SequenceGenerator(name = "seq_id_emp_details", sequenceName = "seq_id_emp_details",
                initialValue = 1, allocationSize = 1)
@Entity
@Table(name = "Employee_Details")
public class EmployeeDetail implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_id_emp_details")
    @Column(name = "id")
    private long id;

    @Column(name = "phone")
    private String phone;
    .
    .
    .
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "employee_id")
    private Employee employee;
    .
    .
    .
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;
    .
    .
    .
    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }

}

EmployeeDaoImp

public class EmployeeDaoImp extends BaseDaoImp<Employee, Long> implements BaseDao<Employee> {


    /**
     * @Function saveOrUpdate
     * @EmployeesEntity employeeEntity
     * @return blResult
     * @type boolean
     */
    @Override
    public boolean saveOrUpdate(Employee entity) {

        boolean blResult = false;

        try {
            entTransaction.begin();
            if(entity.getId() == 0){
                entManager.persist(entity);
            } else {
                entManager.merge(entity);
            }
            entTransaction.commit();
            blResult = true;
        } catch (Exception e) {
            if(entTransaction.isActive()) {
                entTransaction.rollback();
            }
            entManager.clear();
            System.out.println(e.getMessage());
            e.printStackTrace();
        }

        return blResult;
    }


    /**
     * @Function delete
     * @EmployeesEntity employeeEntity
     * @return blResult
     * @type boolean
     */
    @Override
    public boolean delete(Employee employeeEntity) {

        boolean blResult = false;

        try {
            //openEntManager();
            entTransaction.begin();
            entManager.remove(employeeEntity);
            entTransaction.commit();
            blResult = true;
        } catch (Exception e) {
            if(entTransaction.isActive()) {
                entTransaction.rollback();
            }
            entManager.clear();
            System.out.println(e.getMessage());
            e.printStackTrace();
        }

        return blResult;
    }


    /**
     * @Function getById
     * @long lngEmployeeId
     * @return employeeEntity
     * @type EmployeesEntity
     */
    @Override
    public Employee getById(long lngEmployeeId) {

        Employee employeeEntity = null;

        try {

            CriteriaBuilder cBuilder = entManager.getCriteriaBuilder();
            CriteriaQuery<Employee> cQuery = cBuilder.createQuery(Employee.class);
            Root<Employee> root = cQuery.from(Employee.class);
            cQuery.where(cBuilder.equal(root.get("id"), lngEmployeeId));

            TypedQuery<Employee> tQuery = entManager.createQuery(cQuery);
            List<Employee> employeesList = tQuery.getResultList();
            if (!employeesList.isEmpty()) {
                employeeEntity = employeesList.get(0);
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        return employeeEntity;
    }


    /**
     * @Function getList
     * @return employeesList
     * @type List<EmployeesEntity>
     */
    @SuppressWarnings("unchecked")
    @Override
    public List<Employee> getList() {

        List<Employee> employeesList = new ArrayList<Employee>();

        try {
            CriteriaBuilder cBuilder = entManager.getCriteriaBuilder();
            CriteriaQuery<Employee> cQuery = cBuilder.createQuery(Employee.class);
            Root<Employee> root = cQuery.from(Employee.class);
            List<Order> listOrder = new ArrayList<Order>();
            listOrder.add(cBuilder.desc(root.get("id")));
            cQuery.orderBy(listOrder);
            cQuery = this.searchParameters(cBuilder, cQuery, root);

            TypedQuery<Employee> tQuery = entManager.createQuery(cQuery);
            employeesList = tQuery.getResultList();

        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        return employeesList;
    }


    /**
     * @Function search
     * @long lngEmployeeId
     * @long lngPositionId
     * @int intActive
     * @return employeesList
     * @type List<EmployeesEntity>
     */
    public List<Employee> search(long lngEmployeeId, long lngPositionId, int intActive) {

        List<Employee> employeesList = new ArrayList<Employee>();

        try {

            CriteriaBuilder cBuilder = entManager.getCriteriaBuilder();
            CriteriaQuery<Employee> cQuery = cBuilder.createQuery(Employee.class);
            Root<Employee> root = cQuery.from(Employee.class);
            root.fetch("empDetails"); //Solution problem 2

            List<Predicate> predicates = new ArrayList<Predicate>();
            List<Order> listOrder = new ArrayList<Order>();
            listOrder.add(cBuilder.desc(root.get("id")));
            cQuery.orderBy(listOrder);

            if (lngEmployeeId > 0) {
                predicates.add(cBuilder.equal(root.get("id"), lngEmployeeId));
            }
            if (lngPositionId > 0) {
                predicates.add(cBuilder.equal(root.get("position").get("id"), lngPositionId));
            }
            if (intActive < 2) {
                predicates.add(cBuilder.equal(root.get("active"), intActive));
            }
            cQuery.select(root).where(predicates.toArray(new Predicate[] {}));

            TypedQuery<Employee> tQuery = entManager.createQuery(cQuery);
            employeesList = tQuery.getResultList();

        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        return employeesList;
    }
}

我将省略更多的 DaoImp,因为它们都遵循相同的结构

基本示例代码问题1

EmployeeDaoImp employeesDao = new EmployeeDaoImp();
Employee employee = employeesDao.getById(1);
String newName = "Some Name";
boolean sameName = false;

if(employee != null){
    if(employee.getName().equals(newName)){ //SOMETIMES this throws the exception and debugging shows Name attribute to be null
        sameName = true;
    }
}

基本示例代码问题2

EmployeeDaoImp employeesDao = new EmployeeDaoImp();
employeesDao.addOrderBy("id", "desc");
List<Employee> employeesList = employeesDao.getList();
List<String> phoneList = new ArrayList<String>();

for (Employee employee : employeesList) {
    EmployeeDetail details = employee.getEmpDetails();

    phoneList.add(details.getPhone()); //SOMETIMES this throws null pointer exception, it is avoidable if I use the root.fetch as seen on EmployeeDaoImp file
}

基本示例代码问题4

String strNewName = request.getParameter("newName");
String strNewPhone = request.getParameter("newPhone");
long lngEmployeeId = Long.parseLong(request.getParameter("employeeId"));

EmployeeDaoImp employeeDao = new EmployeeDaoImp();
EmployeeDetailDaoImp employeeDetailDao = new EmployeeDetailDaoImp();
Employee employee = employeeDao.getById(lngEmployeeId);
employee.setName(strNewName);

boolean result = false;
if (employeeDao.saveOrUpdate(employee)) {
    EmployeeDetail details = employee.getEmpDetails();
    details.setPhone(strNewPhone);
    if(employeeDetailDao.saveOrUpdate(details)){ //SOMETIMES this throws null pointer exception regarding the parent(Employee)
        result = true;
    }
}

BaseDaoImp & openEntManager 方法的问题 #3 示例

public class BaseDaoImp <T, ID extends Serializable> {

    private static EntityManagerFactory emFactory;

    static {emFactory = Persistence.createEntityManagerFactory("com.daoImp");}

    protected static EntityManager entManager  = emFactory.createEntityManager();

    protected static EntityTransaction entTransaction = entManager.getTransaction();

    private List<String[]> orderBy = new ArrayList<String[]>();

    private List<String[]> conditions = new ArrayList<String[]>();

    private List<String> relations = new ArrayList<String>();


    /**
     * @brief BaseDaoImpl class constructor, manages a session in database
     */
    public BaseDaoImp() {
        if(!entManager.isOpen()) {
            entManager = emFactory.createEntityManager();
        }
    }
    .
    .
    .

    public void closeEntManager() {
        try {
            entManager.close();
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

    public void openEntManager() {
        try {
            if(!entManager.isOpen()) {
                entManager = emFactory.createEntityManager();
            }
            entManager.clear(); //SOMETIMES this throws session closed error
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

    public void clearCache() {
        try {
            entManager.clear();
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}

补充说明:

  1. clearCache 方法我仅在用户成功登录以直接从数据库而非一级缓存中提取数据时使用
  2. openEntManager 方法仅用于测试目的,除此之外不再使用
  3. 这是我对 Spring/Hibernate 的第一次体验,欢迎大家指点和批评
  4. 在数据库中存在正确实现功能所需的所有寄存器,显然我的不是
  5. 对不起,如果我的英语或编辑不好

【问题讨论】:

    标签: java spring hibernate entitymanager hibernate-entitymanager


    【解决方案1】:

    对于问题1,虽然你的员工对象不为null,但属性“name”有时可能为null,那么null没有equals()方法,会抛出空指针异常

    【讨论】:

    • 不是这样,数据库中的字段不为空,并且不管怎样都会抛出这个异常
    猜你喜欢
    • 2015-12-06
    • 2014-04-10
    • 2013-06-08
    • 2023-03-23
    • 2012-08-10
    • 1970-01-01
    • 1970-01-01
    • 2017-03-26
    • 1970-01-01
    相关资源
    最近更新 更多