Deadlock when we we have dependent entities in hibernate and try to update table using multiple threads in Vertica - sql

I have two java classes. Father.java and Children.java
#Entity
#Table(name = "FATHER")
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
class Father implements Cloneable
{
#Id
#Column(name = "father_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long fatherId;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "father_id")
#Fetch(value = FetchMode.SUBSELECT)
private List<Children> children = new ArrayList<Children>();
//getter and setters and public constructors
}
#Entity
#Table(name = "Children")
class Children implements Comparable<Children>
{
#JsonIgnore
#Id
#Column(name = "children_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long child_id;
#JsonIgnore
#Column(name = "father_id")
private long fatherId;
//public constructors and getters and setters
}
public interface RelationDao{
public Father update() throws Exception;
}
#Repository("relationDao")
#EnableTransactionManagement
#Transactional
public RelationDaoImpl{
#Override
#Transactional("txManager")
public Father update(Father father)
{
father = merge(father);
//added retry logic as well also father is updated with a new child which is why merge
}
}
I receive the Deadlock X exception if several threads visit the same table (entity father) to updates with distinct row entries, even though the records are different.
Is there any way to fix why the entire table locks up instead than just one row?
Even though I haven't updated or added anything to the code, the transaction isolation level is SERIALIZABLE.
DB system is Vertica

Explained here, if anyone is coming here to check why Vertica doesn’t support row level locks for updates or delete. https://stackoverflow.com/a/69917383/8799862
So I used synchronized to perform thread-safe updates and deletes.

Related

Hibernate LazyLoading initialization of List

I've typical User and Comment-Models. One user has more comments.
On one usecase i want to get only a user from db, without comments.
I thought, as soon i tell "getComments()", so only in this moment, my List will initialized with
something like "select comment from Comment c where c.userId = 1" from Hibernate.
But my List of comments will be initialized everytime when i say findyById or "select user from User".
#Entity
#Getter #Setter
#ToString(exclude = {"comments")
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class User implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Builder.Default
#OneToMany(mappedBy="user", fetch = FetchType.LAZY)
private List<Comment> comments = new ArrayList<>();
}
My Comment Model:
#Entity
#Getter #Setter
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class Comment implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Builder.Default
#ManyToOne(fetch = FetchType.LAZY)
private User user; }
UserRepository:
public interface UserRepository extends JpaRepository<User, Long> {
#Query("SELECT user FROM User user WHERE user.id =:id")
Optional<User> findUserById(#Param("id") long id); }
When i tell:
userRepository.findUserById(1);
So i see at first only one select-statment for user.
Few seconds later i see next statment for comment, but i did not tell "user.getComments()"
So how can i get User-Model without any Lazy-List's with related Object?

how to get entities with many to may dependency

This is project entity which I need to get by current user Id:
#Entity
#Table(name = "project")
public class Project implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToMany
#JoinTable(name = "project_user",
joinColumns = #JoinColumn(name="projects_id", referencedColumnName="id"),
inverseJoinColumns = #JoinColumn(name="users_id", referencedColumnName="id"))
private Set<User> users = new HashSet<>();
}
this is user entity whichs Id I'll use to get products:
#Entity
#Table(name = "jhi_user")
public class User extends AbstractAuditingEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToMany(mappedBy = "users")
private Set<Project> projects = new HashSet<>();
}
Repositories classes extend JpaRepository class. How I can get all projects for current user Id?
Native SQL statement that I can use is:
SELECT * FROM project WHERE id IN (SELECT projects_id FROM project_user WHERE users_id = ?);
It should be as simple as this...
User user = userRepository.findById(100L);
Set<Projects> projects = user.getProjects();
Because of your mapping, JPA takes care of the rest.

JPA Entity with hierachy relationship

I have the following Entity
#Entity
public class Project implements Serializable {
#Id
private Integer project_id;
private String project_name;
other attributes
#OneToOne
#JoinColumn(name = "lead_emp_no", referencedColumnName = "emp_no")
private Employee projectLead;
// but the following two relationships need to be a connect by:
#OneToOne
#JoinColumn(name = "lead_boss_emp_no", referencedColumnName = "emp_no")
private Employee projectLeadBoss;
#OneToOne
#JoinColumn(name = "lead_bosses_boss_emp_no", referencedColumnName = "emp_no")
private Employee projectLeadBossesBoss;
With this setup, we have to manually maintain the employee numbers for the Lead's boss and the Lead's Boss's boss. This relationship is [somewhat] already available knowing the projectLead employee:
The Employee Entity is as follows:
#Entity
public class Employee implements Serializable {
#Id
private Integer emp_no;
private Integer bosses_emp_no;
Is it possible to get my Project entity to connect to the boss and bosses Employee based on projectLead? In single query I'd like to get a table of all projects and their lead's hierarchy. I'm open to entity redesign.
You can replace the bosses_emp_no in Employee should with a more helpful boss:
#Entity
public class Employee implements Serializable {
#Id
private Integer emp_no;
#OneToOne
#JoinColumn(name = "boss_emp_no", referencedColumnName = "emp_no")
private Employee boss;
Then you simply add a couple of delegating methods to Project
public Employee getProjectLeadBoss() {
return this.projectLead.getBoss();
}
public Employee getProjectLeadBossesBoss() {
return this.getProjectLeadBoss().getBoss();
}

Hibernate 4 and Postgres : How to create a sequence per table?

I use Hibernate 4 to use mapping to a Postgres database. Before doing mapping i create first java entities. And then, i use a java class to generate sql script from my entities. Here is my entities :
User entity
#Entity
#Table(name="myusers")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(name="fistname")
private String firstName;
#Column(name="lastName")
private String lastName;
....
}
Project entity
#Entity
#Table(name="projects")
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(name="title")
private String title;
#Column(name="description")
private String description;
..
}
I've noticed that #GeneratedValue(strategy = GenerationType.AUTO) produces the same sequence for table myusers and projects. If i create the first record on myusers table the id will have "1" as value and then when i create the first record in table projects, this record will have id =2. They use both the same sequence.
I want to know how i cannot modify my entities to specify to Hibernate to create a sequence for each table.
If you're on a recent Hibernate, try:
#GeneratedValue(strategy = GenerationType.IDENTITY)
If it still uses a sequence per table use:
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator="mytable_id_seq")
#SequenceGenerator(name="mytable_id_seq", sequenceName="mytable_id_seq", allocationSize=1)
See hibernate could not get next sequence value

Map (integer integer) mapping in hibernate

How would you annotate this bean to be mapped in hibernate ?
#Entity
public class PerformanceValues implements Serializable{
private static final long serialVersionUID = 1234850675335166109L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
//key is mass, value is distance needed
private Map<Integer, Integer> massToDist;
}
Each performanceValues entity has a unique map, and each map can be related to only one PerformanceValues (I guess this is a oneToOne relationship)
Thanks