I have created a sample web application. I am using MS SQL Server 2008 as database and hibernate + annotations to access the database. My hibernate configuration xml is as below.
The problem is, the Criteria.list() returns an empty list, and also I am seeing a '?' in the generated HSQL instead of the parameter I am passing in the Criteria.
<session-factory name="">
<property name="hibernate.connection.driver_class">sun.jdbc.odbc.JdbcOdbcDriver</property>
<property name="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>
<property name="hibernate.connection.url">jdbc:odbc:dbname</property>
<property name="connection.pool_size">10</property>
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<property name="hibernate.connection.username"></property>
<property name="hibernate.connection.password"></property>
<mapping class="com.demo.Person" />
</session-factory>
This is my annotated bean
#Entity
#Table(name = "person")
public class Person implements Serializable {
public Person(){
}
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Basic(optional = false)
#Column(name = "personid")
private Integer personid;
#Basic(optional = false)
#Column(name = "firstname")
private String firstname;
#Column(name = "lastname")
private String lastname;
#Basic(optional = false)
#Column(name = "phone")
private String phone;
#Column(name = "mobile")
private String mobile;
#Column(name = "street")
private String street;
#Basic(optional = false)
#Column(name = "city")
private String city;
#Basic(optional = false)
#Column(name = "country")
private String country;
#Basic(optional = false)
#Column(name = "bussinessowner")
private int bussinessowner;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "resultid1")
private Collection<Recent> recentCollection;
//setters & getters
}
And the code I am running is
Session session;
List list = new ArrayList();
try{
session = HibernateUtil.getSessionFactory().openSession();
Criteria criteria = session.createCriteria(Person.class);
criteria.add(Restrictions.like("firstname", name, MatchMode.START));
list= criteria.list();
System.out.println(list.size());
}catch (Exception e) {
e.printStackTrace();
}
Generated HSQL :
Hibernate: select this_.personid as personid2_0_, this_.city as city2_0_, this_.country as country2_0_, this_.firstname as firstname2_0_, this_.lastname as lastname2_0_ from person this_ where this_.firstname like ?
Other than this I am not getting any exception either. Can you please help me out with this.
Thanks !
Does changing it to criteria.add(Restrictions.like("firstname", name + "%")); help?
And, by the way, ? is correct parameter placeholder for jbdc statements.
'?' is the place holder for parameters in JDBC statements. You can't see its actual value, that's all. There is no problem with it, just the tracing with hibernate remains incomplete.
If you want to see the actual value for '?', then you have to use an extra product like log4jdbc.
#Rakesh Try below code:
criteria.add(Restrictions.ilike("firstname", name +"%"));
Instead of this line
criteria.add(Restrictions.like("firstname", name, MatchMode.START));
try
criteria.add(Restrictions.like("firstname", name, MatchMode.ANYWHERE));
OR
criteria.add(Restrictions.ilike("firstname", name, MatchMode.ANYWHERE));
It will gerenerate SQL as firstname like '%abcd%' , if you pass firstname as "abcd"
Can you simply try this
session = HibernateUtil.getSessionFactory().openSession();
List<Person> personList = session.createQuery("Select * from Person p where p.firstname like 'rake%'").list();
System.out.println("Person result :" + personList .size());
Related
It's may day 5 with Hibernate. I'm learning JPA. My question is very much similar to:
JPA + Hibernate: How to define a constraint having ON DELETE CASCADE
But the problem is:
It was asked 8 years ago. So the versions will not match today.
The OP didn't mention the version of Hibernate or MySQL or Java.
There is no accepted answer.
I've two tables student and guide. They are linked with a foreign key:
I didn't create these tables. Hibernate created them for me because I'm using these annotations in my student class:
#ManyToOne(cascade={CascadeType.PERSIST, CascadeType.REMOVE})
#JoinColumn(name="guide_id")
private Guide guide;
It is clearly seen that Raj and Tanzeel have same guide i.e Joe. I want to maintain the referential integrity constraint. That means If I delete Raj then Joe will also get deleted. That means Tanzeel will be left without any guide. That should not happen right? But this is what I'm facing.
Here is my code:
Main.java
public class Main {
public static void main(String[] args) {
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction txn = session.getTransaction();
try {
txn.begin();
// deleting Student[id=2L] (using CascadeType.REMOVE)
Student student = (Student) session.get(Student.class, 2L);
session.delete(student);
txn.commit();
} catch(Exception e) {
...
}
}
}
Student.java
#Entity
public class Student {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Column(name="enrollment_id", nullable=false)
private String enrollmentId;
private String name;
#ManyToOne(cascade={CascadeType.PERSIST, CascadeType.REMOVE})
#JoinColumn(name="guide_id")
private Guide guide;
public Student() {}
public Student(String enrollmentId, String name, Guide guide) {
this.enrollmentId = enrollmentId;
this.name = name;
this.guide = guide;
}
...
}
Guide.java
#Entity
public class Guide {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#Column(name = "staff_id", nullable = false)
private String staffId;
private String name;
private Integer salary;
public Guide() {}
public Guide(String staffId, String name, Integer salary) {
this.staffId = staffId;
this.name = name;
this.salary = salary;
}
}
Some info from my hibernate.cfg.xml
<session-factory>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">update</property>
<!-- Use Annotation-based mapping metadata -->
<mapping class="entity.Student"/>
<mapping class="entity.Guide"/>
</session-factory>
The problem is, when i deleted Raj, his guide Joe also got deleted and there was no exception seen regarding foreign key violation. Guide table has only Mike now and Tanzeel is referring to the guide Joe who doesn't even exists now.
My versions:
Java 11
mysql-connector-java 8.0.26
hibernate-core 5.5.6.Final
Please pitch in.
in your case, I would have used the bidirectional association instead of the unidirectional one.
So you're Guide entity would have seen like this,
#Entity
public class Guide {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#OneToMany(mappedBy="guide")
private List<Student> students;
#Column(name = "staff_id", nullable = false)
private String staffId;
private String name;
private Integer salary;
public Guide() {}
public Guide(String staffId, String name, Integer salary) {
this.staffId = staffId;
this.name = name;
this.salary = salary;
}
}
I suggest you take a look at other examples on this page.
Hope it could help you.
--Edited--
I suggest you check this link, Thorben clarifies, why you shouldn't use CascadeType.REMOVE for -ToMany associations. In the end, you should remove the entity yourself using EntityManager or remove method.
And the above entity change of mine is irrelevant. Ignore it please.
CascadeType.REMOVE: It means that the related entities are deleted when the owning entity is deleted.
If you only have it mapped unidirectionally (Student to Guide), and you eliminate in cascade it is logical the behavior you are receiving.
Don't use cascade.REMOVE and add the other relation (Guide to Student) I think it would be the expected behavior.
#Entity
public class Student {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Column(name="enrollment_id", nullable=false)
private String enrollmentId;
private String name;
#ManyToOne()
#JoinColumn(name="guide_id")
private Guide guide;
}
#Entity
public class Guide {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#Column(name = "staff_id", nullable = false)
private String staffId;
private String name;
private Integer salary;
#OneToMany(mappedBy="guide")
private List<Student> students;
}
Currently we are doing a performance review and improvement of the DB CRUD function of the application and one of the reviews was using Hikari connection pool and a later version of Hibernate and Hibernate-HikariCP for our tests.
We are running this by upgrading the Hibernate version from 5.2.10 to 5.2.16, with Hikari at version 3.1.0. This entire exercise was tested with Tomcat 8 and MSSQL 2016.
For simplicity purposes, we tested on one simple search with one search condition using the entity User.
Hibernate XML Configuration:
<hibernate-configuration>
<session-factory>
<property name = "hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>
<property name="show_sql">true</property>
<!-- Hikari specific properties -->
<property name="hibernate.connection.provider_class">com.zaxxer.hikari.hibernate.HikariConnectionProvider</property>
<property name="hikari.maximumPoolSize">30</property>
<property name="hikari.idleTimeout">300000</property>
<property name="hikari.maxLifetime">1800000</property>
<!-- Database connection properties -->
<property name="hibernate.hikari.dataSourceClassName">com.microsoft.sqlserver.jdbc.SQLServerDataSource</property>
<property name="hibernate.connection.url">jdbc:sqlserver://192.168.0.102:1433;databaseName=migration1;user=sun;password=p#ssw0rd;</property>
<property name = "hibernate.connection.username">sun</property>
<property name = "hibernate.connection.password">p#ssw0rd</property>
<mapping class="com.hib.model.Outlet"/>
<mapping class="com.hib.model.Receipt"/>
<mapping class="com.hib.model.Cashier"/>
<mapping class="com.hib.model.Category"/>
<mapping class="com.hib.model.Item"/>
<mapping class="com.hib.model.PayMethodName"/>
<mapping class="com.hib.model.Pos"/>
<mapping class="com.hib.model.Purchase"/>
<mapping class="com.hib.model.User"/>
</session-factory>
</hibernate-configuration>
The HibernateUtil class is quite simple, currently as:
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
// Create the SessionFactory from standard (hibernate.cfg.xml)
// config file.
Configuration configuration = new Configuration().configure();
StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties());
sessionFactory = new Configuration().configure().buildSessionFactory(builder.build());
} catch (Throwable th) {
System.err.println("Initial SessionFactory creation failed " + th);
throw new ExceptionInInitializerError(th);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown() {
// Close caches and connection pools
getSessionFactory().close();
}
}
The User Entity, annotated, excluding the getter / setters:
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Version;
import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.XmlRootElement;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.UpdateTimestamp;
#Entity
#Table(name = "User")
#XmlRootElement
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#Column(name = "id")
#NotNull
#GeneratedValue(generator="`id`")
#GenericGenerator(name="`id`", strategy = "increment")
private Integer id;
#NotNull
#Column(name = "FullName")
private String fullName;
#Column(name = "NickName")
private String nickName;
#Column(name = "Tel")
private String tel;
#Column(name = "Rank")
private String rank;
#NotNull
#Column(name = "Email")
private String email;
#NotNull
#Column(name = "Password")
private String password;
#Lob
#Column(name = "PhotoUpload")
private String photoUpload;
#Version
#Column(name = "CreateDate")
#CreationTimestamp
#Temporal(TemporalType.TIMESTAMP)
private Date createDate;
#Version
#Column(name = "EditDate")
#UpdateTimestamp
#Temporal(TemporalType.TIMESTAMP)
private Date editDate;
#Column(name = "CreateBy")
private String createBy;
#Column(name = "ActiveInd")
private String activeInd;
#Column(name = "LastLogin")
#Temporal(TemporalType.TIMESTAMP)
private Date lastLogin;
#Column(name = "tenant_id")
private String tenantId;
#NotNull
#Column(name = "group_id")
private String groupId;
public User() {
}
public User(Integer id, String fullName,String nickName,String tel,String rank,String email,String password,String photoUpload,Date createDate,Date editDate,String createBy,String activeInd,Date lastLogin, String tenantId, String groupId) {
this.id = id;
this.fullName = fullName;
this.nickName = nickName;
this.tel =tel;
this.rank=rank;
this.email =email;
this.password = password;
this.photoUpload = photoUpload;
this.createDate =createDate;
this.editDate =editDate;
this.createBy =createBy;
this.activeInd = activeInd;
this.lastLogin=lastLogin;
this.tenantId= tenantId;
this.groupId =groupId;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof User)) {
return false;
}
User other = (User) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "com.example.dao.User[ id=" + id + " ]";
}
The function of searching the particular Users is in this method of the User Service class:
#Override
public List<User> getUserById(Integer id) {
List<User> result = null;
Session session = getSession();
try {
Criteria criteria = getSession().createCriteria(User.class);
Criteria criteria = getSession().(User.class);
criteria.add(Restrictions.eq("id", id));
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
result = query.getResultList();
}catch (HibernateException e){
userLogger.error("Error found: " + e);
}finally {
if (session != null)
session.close();
}
return result;
}
When tested, if the original C3P0 connection pool is used, the search function above will return the expected result of the matching record corresponding to the Id number passed in (numeric value).
However, when switched to HikariCP, the result returns null. However, if we write a NativeQuery instead of Criteria, it does not get affected.
Subsequently, we tried three alternatives to see if it works but with different errors:
Option 1: - returns an IllegalArgumentException, entity User not mapped
TypedQuery<User> query = session.createQuery("select u from "+User.class.getSimpleName()+" u",User.class) ;
result = query.getResultList();
Option 2: - returns an IllegalArgumentException, not an entity User.
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<User> cq = cb.createQuery(User.class);
Root<User> root = cq.from(User.class);
cq.select(root);
Query<User> q = session.createQuery(cq);
result = q.getResultList();
Option 3 - returns a mapping exception, unknown entity User:
String sql = "SELECT * FROM USER_LOG WHERE id = :number_id";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(User.class);
query.setParameter("number_id", id);
result = query.list();
As HikariCP has done a lot of improvements for the other Native Queries, we felt it is better if we can still keep on using that CP in favor of the C3P0 pool. However, we are still stuck as in unsure to which approach in the Service class method is best used.
We appreciate any advise on help on this. Thanks.
I am getting strange error Caused by:
java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint
While executing my below code:
Product DAO.java
#Id
#Column(name = "no", columnDefinition = "NUMBER")
private int serial_number;
//No getter and setter for this field
#Column(name = "fname", columnDefinition = "VARCHAR2(50)")
private int fname;
#Column(name = "lname", columnDefinition = "VARCHAR2(50)")
private int lname;
// Getter and setter for fname and lname
ProductService.java
Product po = new Product();
po.setfname = "Tom";
po.setlname = "John";
//I am not setting 'no' field value since I have created sequence in my oracle table to auto increment the value.
When I am running this code, I am getting unique constraint error on field 'no'. Can anyone help me in identifying what I am doing wrong in my code. When I have already created sequence for 'no' field in my table, do I need to make any change in config file or code? Since its the production database, I do not know the sequence name also.
hibernate-cgf.xml
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="hibernate.connection.url">jdbc:oracle:thin:#localhost:1521:xe</property>
<property name="hibernate.connection.password">pass</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">update</property>
<mapping class="dao.Product"></mapping>
</session-factory>
</hibernate-configuration>
Your id field serial_number is an int which is initialized to zero, and your mapping for #Id does not include a #GeneratedValue annotation, so hibernate will assume you are assigning the id manually and save it as zero every time you persist an object, causing the SQLIntegrityConstraintViolationException. You need to add a #GeneratedValue annotation and you can also choose a strategy, like this:
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "no", columnDefinition = "NUMBER")
private int serial_number;
I am using plain java to hibernate standalone application with Hibernate Envers for getting updates of changes made in table's columns, I am using sql server as my Database, and I am new in envers.
Here is my "CustomRevisionEntity.java"
#Entity
#AuditTable("REVINFO")
#RevisionEntity(CustomRevisionListener.class)
public class CustomRevisionEntity {
#Column (name = "USERNAME", length = 50)
private String username;
#Id
#GeneratedValue
#RevisionNumber
#Column (name = "REV", unique = true, nullable = false)
private int id;
#Temporal(TemporalType.DATE)
#Column (name = "REVTSTMP", nullable = false, length = 15)
#RevisionTimestamp
private Date timestamp;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getTimestamp() {
return timestamp;
}
public void setTimestamp(Date timestamp) {
this.timestamp = timestamp;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
CustomRevisionListener.java
public class CustomRevisionListener implements RevisionListener {
public void newRevision(Object revisionEntity) {
CustomRevisionEntity revision = (CustomRevisionEntity) revisionEntity ;
String userName = Hibernate_Connection.getloggedUser();
revision.setUsername(userName);
}
}
Hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
<property name="hibernate.connection.url">jdbc:sqlserver://localhost:1433;instance=SQLEXPRESS_2012;DatabaseName=ETS_V11_DEV;integratedSecurity=true</property> -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> -->
<property name="show_sql">true</property>
<property name="use_sql_comments">true</property>
<property name="hbm2ddl.auto">update</property>
<mapping class= "Domain_hibernate_SQLServer.Domain"/>
<mapping class= "Domain_hibernate_SQLServer.CustomRevisionEntity"/>
</session-factory>
</hibernate-configuration>
Problem: While using hbm.xml file then it is adding value on username column,
but while I am using Annotation for getting value that time is taking null value as it is not recognizing extra column property that I have added, but
While using annotation, its inserting null values in username columns
It is taking values like this with annotation while seeing sql code on console
/* insert org.hibernate.envers.DefaultRevisionEntity
*/ insert
into
REVINFO
(REVTSTMP)
values
(?)
Table has only 3 columns, 1 is REV, i.e, autoincrement, 2nd is REVTSTMP, nd 3rd is USERNAME, and Its not taking username,
What I am missing, If you need more information then please comment
I think the problem comes from your annotation config so can post your hbm.xml file and the class used for the anotation config?
I have a problem with lazy initialisation. I can't find a solution.
Exception:
[pool-1-thread-12] ERROR:12:20:14.840 o.h.LazyInitializationException - failed to lazily initialize a collection of role: de.beeld.forges.domain.Server.applications, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: de.beeld.forges.domain.Server.applications, no session or session was closed
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380)
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372)
[pool-2-thread-1] ERROR:12:20:14.840 o.s.s.support.MethodInvokingRunnable - Invocation of method 'readStatusCache' on target class [class de.beeld.forges.task.annotation.ScheduledProcessor$$EnhancerByCGLIB$$ee649dc3] failed
java.util.ConcurrentModificationException: null
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
hibernate.xml
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
p:dataSource-ref="standardDataSource" p:lobHandler-ref="defaultLobHandler">
<property name="annotatedClasses">
<list>
<value>de.beeld.forges.domain.Server</value>
<value>de.beeld.forges.domain.Application</value>
<value>de.beeld.forges.domain.Forge</value>
</list>
</property>
</property>
</bean>
<bean id="defaultLobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" />
<!-- Read in DAOs from the hibernate package -->
<context:component-scan base-package="de.beeld.forges.dao" />
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory" />
<bean id="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan base-package="de.beeld">
<context:exclude-filter expression="org.springframework.stereotype.Controller"
type="annotation" />
<context:exclude-filter expression="org.springframework.stereotype.Repository"
type="annotation" />
</context:component-scan>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
readStatusCache method:
public void readStatusCache() {
String execCommand = "java -jar ...";
List<Future<Map<Long, Integer>>> list = new ArrayList<Future<Map<Long, Integer>>>();
String serverName = null;
for (Server server : serviceFacade.getServers()) {
serverName = server.getName();
Callable<Map<Long, Integer>> worker = new ApplicationStatusReader2(server.getApplications(),
sshConnector, execCommand, serverName);
Future<Map<Long, Integer>> submit = this.serviceFacade.getExecutor().submit(worker);
list.add(submit);
}
for (Future<Map<Long, Integer>> future : list) {
//do stuff
}
}
Server.java
#Entity
#org.hibernate.annotations.Entity(dynamicUpdate = true)
public class Server implements DomainObject, Comparable<Server> {
private static final long serialVersionUID = -8920952435734596243L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(unique = true, nullable = false)
#NotEmpty
private String name;
#Column(nullable = false)
#NotEmpty
#Pattern(regexp = "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$", message = "The ip must be in format xxx.xxx.xxx.xxx")
private String ip;
#Column(nullable = false)
#NotEmpty
private String fqdn;
#OneToMany(mappedBy = "server", fetch = FetchType.LAZY)
private List<Application> applications;
#Version
private int version;
//getter and setter
}
Application.java
#Entity
public class Application implements DomainObject {
private static final long serialVersionUID = -8127137156319959239L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
private Server server;
#Column(nullable = false)
#NotEmpty
private String name;
#Column(nullable = false)
#NotEmpty
private String location;
#Column(nullable = false)
#NotEmpty
private String binDir;
private String confDir;
private boolean isContainer = false;
private String containerDir;
private String startup = "startup.sh";
private String shutdown = "shutdown.sh";
#ManyToOne(fetch = FetchType.LAZY)
#Fetch(FetchMode.JOIN)
private Forge forge;
#ManyToOne(fetch = FetchType.LAZY)
#Fetch(FetchMode.JOIN)
private Application parent;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private List<Application> offsprings;
#NotEmpty
private String blueprint;
private Integer replaceable = 0;
private Integer running = 0;
#Version
private int version;
//getter and setter
}
I don't really know why I cant read the list of applications from the server
If anybody could help it would be great.
Most likely because you're setting applications collection to lazy load. So when you return from the initial call to serviceFacade.getServers(), my guess is that you no longer have the session opened that was used to fetch the list of servers.
As a result, when you iterator through the applications, the session was closed, so it can't load the actual contents of the collection.
You have three possibilities:
Keep the session open (google for binding hibernate session to thread, or if the readStatusCache method is in a spring managed object, just add an #Transactional annotation to it, or the entry point from which it is called).
Change the applications collection to be an eager load
have your dao layer fully initialize the applications collection (see Hibernate.initialize method) while the session is still open.
The two loops
for (Server server : serviceFacade.getServers()) {
serverName = server.getName();
Callable<Map<Long, Integer>> worker = new ApplicationStatusReader2(server.getApplications(),
sshConnector, execCommand, serverName);
Future<Map<Long, Integer>> submit = this.serviceFacade.getExecutor().submit(worker);
list.add(submit);
}
for (Future<Map<Long, Integer>> future : list) {
//do stuff
}
are being called by two separate threads simultaneously. You can check if this is the case by synchronizing the readStatusCache() method. But this should be done in the Spring layer. Are you using transactions etc. properly?
Please read this answer for more on thread safety with spring and hibernate. Spring-Hibernate used in a webapp,what are strategies for Thread safe session management
When I got the same exception, the solution was to add the #Transactional annotation to the method in the controller.