Ошибочное поведение EntityManager

давний браузер впервые задает вопрос.

Я столкнулся с несколькими проблемами в своем приложении, и я не знаю, есть ли у них что-то общее, меня сбивает с толку то, что они не происходят регулярно или по шаблону, иногда одна сущность иногда другая, в раз один и тот же запрос, разделенный секундами, дает другой результат. Проблемы вот в чем:

  1. Когда я извлекаю объект, он имеет некоторые атрибуты correct(id) и другие null, поэтому, когда я оцениваю, является ли объект null, он возвращает false, но когда я пытаюсь работать с одним из атрибутов, возникает исключение нулевого указателя
  2. Когда я пытаюсь получить отношение, оно возвращает null, это я решил, выбрав отношение с запросом, но я не могу использовать это решение везде.
  3. Иногда entityManager закрывается без каких-либо объяснений, я проверяю, открыт ли сеанс, чтобы открыть его в противном случае, однако он оценивается как истинный, но в следующей строке кода, где я пытаюсь выполнить операцию, он выдает сеанс закрыт ошибка
  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 + "]";
    }
}

Сведения о сотруднике

@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;
    }

}

СотрудникDaoImp

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 ​​и проблемы №3 в методе openEntManager

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. Извините, если мой английский или редакция плохи

person Néstor Josué R. Guerrero    schedule 16.01.2020    source источник


Ответы (1)


Для проблемы 1, хотя ваш объект сотрудника не является нулевым, но свойство «имя» может иногда иметь значение null, тогда null не имеет метода equals(), будет выдано исключение нулевого указателя

person nonono    schedule 16.01.2020
comment
Это не так, поля в базе данных не равны нулю, и это исключение возникает независимо от того, да, у меня есть некоторые пустые поля, но они обрабатываются соответствующим образом. - person Néstor Josué R. Guerrero; 16.01.2020