I wanted to save many entities using Hibernates Session in one call, so i created this code:
public void persistOrUpdateAllTrades(List<Trade> objects) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
Session session = (Session)entityManager.getDelegate();
try {
FlushMode lastFlushMode = session.getFlushMode();
session.setFlushMode(FlushMode.MANUAL);
for(Trade trade: objects) {
if(session.get(Trade.class, trade.getId()) == null){
session.save((Object)trade);
}
}
session.flush();
session.setFlushMode(lastFlushMode);
} catch (Throwable e) {
throw new RuntimeException(e.getMessage(),e);
}
}
It usually works well, but sometimes execution stops/hangs at if(session.get(Trade.class, trade.getId()) == null) and i have no idea why. It doesn't throw any exception, and application doesn't stop. Application uses MySQL server running at localhost. Any hints?
You're not closing the EntityManager. This is leaks resources, most often connections from a connection pool. Eventually the pool has no more connections available, so it just blocks until it gets a connection available (which in your case is never). The quick fix would just be to do a entityManager.close() at the bottom of your method.
Related
I code my Test project and it is prohibited to use Spring and Hibernate there.
I wanted to manage my transactions from Service layer.
For this I have created a class that gets a Connection from the pool and puts it in the ThreadLocal.
This is an example of the fields and the method.
private static ThreadLocal<Connection> threadLocalConnection;
private ComboPooledDataSource comboPooledDataSource ;
public boolean createConnectionIfAbsent() {
boolean isConnectionCreated = false;
try {
Connection currentConnection = threadLocalConnection.get();
if(currentConnection == null) {
Connection conn = this.comboPooledDataSource.getConnection();
conn.setAutoCommit(false);
threadLocalConnection.set(conn);
isConnectionCreated = true;
}
} catch (SQLException e) {
e.printStackTrace();
}
return isConnectionCreated;
}
The class has also close, rollback methods.
Here is the example of how I manage Connections in a Service Layer.
public BigDecimal getTotalOrdersCount() {
boolean connectionCreated = DBManager.getInstance().createConnectionIfAbsent();
BigDecimal ordersCount = BigDecimal.ZERO;
try {
ordersCount = orderDao.getRowNumber();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
if (connectionCreated) DBManager.getInstance().closeConnection();
}
return ordersCount;
}
Dao just uses this to get the connection.
Connection connection = DBManager.getInstance().getConnection();
I found no other way to manage connections in a Servlet project from a Service layer, could you please tell if it is ok? If not - what drawbacks does it have and what should I use instead.
UPD:
Please pay attention to this Service method. Let's assume that Each method in DAO gets the Connection from a pool and closes it.
I do know that I need connection.setAutoCommit(false); to start a transaction, but what to do it in this kind of a situation?
When a single methods calls 2 DAO.
Just give up on a transaction handling?
void setStatusDeclinedAndRefund() {
// sets Order status to DECLINED
// refund money to user's balance
}
No.
Don't second guess the connection pool. Use it in the standard way: get a connection, use it, close it.
There is no need to use the same connection for every database interaction in a given thread. Also, you'll have serious liveliness problems if you allocate each thread a connection, because typically there are way more request processing threads than there are connections in the pool.
We are trying to get the connection object from the EntityManager
Below is the sample code
final Session unwrap = proxy.unwrap(Session.class);
unwrap.doWork(new Work()
{
#Override
public void execute(Connection connection) throws SQLException
{
PreparedStatement ps = connection.prepareStatement(MY_QUERY);
for (Object value : valueSet)
{
....
....
ps.addBatch();
}
try
{
int[] ints = ps.executeBatch();
} finally
{
ps.close();
}
}
});
This works fine .
The concern we have is that when this code is invoked , everytime getConnection is called on the DataSource. Does that mean a new connection is obtained from the pool ?
This has performance impact in our use case .
Our understanding is that the current active connection will be utilised.
Is the understanding incorrect ?
The Hibernate documentation says:
Controller for allowing users to perform JDBC related work using the Connection managed by this Session.
So it is the (single) Connection used by the Session.
Everything else would be a Bug.
Im working on a java standAlone project. I need to use hibernate in a MultiThread application but i just cant figure it out how to set up this correctly.
Each Thread deals with the same process of the others.
Everything goes Ok when i run it in a Non-Async way, but when i call the same thing using threads, hibernate just don't work fine.
Can anyone please explain me what's the correct way to use Hibernate in a multiThread Java Stand-Alone App?
Hibernate Util
public class HibernateUtil {
private static final Session session;
static {
try {
SessionFactory sessionFactory;
Properties properties = new Properties();
properties.load(new FileInputStream("middleware.properties"));
Configuration cfg = new Configuration().configure();
cfg.addProperties(properties);
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(cfg.getProperties()).build();
sessionFactory = cfg.buildSessionFactory(serviceRegistry);
session = sessionFactory.openSession();
} catch (IOException | HibernateException he) {
JOptionPane.showMessageDialog(null, DataBaseMessage.CONNECTION_ERROR.getMessage(), DataBaseMessage.CONNECTION_ERROR.getTitle(),JOptionPane.ERROR_MESSAGE);
throw new ExceptionInInitializerError(he);
}
}
public static Session getSession() {
return session;
}
The Error comes here
TbHistoDespachos despacho = Dao.findDespachoByTagId(element.getChild("tagID").getText());
public synchronized List<TbHistoDespachos> ExractDespachoAndNotify(String data, String nombreConexion) {
List<TbHistoDespachos> despachos = new ArrayList<>();
String nombreConexionUpp = nombreConexion.toUpperCase();
try {
Document doc = convertStringToDocument(data);
if (!doc.getRootElement().getChild("reply").getChild("readTagIDs")
.getChildren().isEmpty()) {
for (Element element : doc.getRootElement().getChild("reply").
getChild("readTagIDs").getChild("returnValue")
.getChildren()) {
TbHistoDespachos despacho = Dao.findDespachoByTagId(element.getChild("tagID").getText());
if (despacho != null) {
if(evaluateDespacho(nombreConexionUpp, despacho)){
despachos.add(despacho);
}
}
}
}
} catch (JDOMException | IOException ex) {
JOptionPane.showMessageDialog(null, FilesMessageWarnings.NOTIFICATION_SAP_WARNING.
getMessage().replace("&nombreConexion", nombreConexion).replace("&tagID", ""),
FilesMessageWarnings.NOTIFICATION_SAP_WARNING.getTitle(), JOptionPane.WARNING_MESSAGE);
}
return despachos;
}
Here is the DAO
public class Dao {
private static Session sesion;
public static TbHistoDespachos findDespachoByTagId(String tagId) {
TbHistoDespachos despacho = null;
try {
startTransmission();
despacho = (TbHistoDespachos)sesion.createQuery("FROM TbHistoDespachos WHERE TAG_ID =:tagId")
.setParameter("tagId", tagId)
.uniqueResult();
stopTransmission();
} catch (HibernateException he) {
System.out.println("error: " + he.getMessage());
JOptionPane.showMessageDialog(null, DataBaseMessage.QUERY_ERROR.getMessage(),
DataBaseMessage.QUERY_ERROR.getTitle(), JOptionPane.ERROR_MESSAGE);
}
return despacho;
}
private static void startTransmission() {
sesion = HibernateUtil.getSession();
sesion.getTransaction().begin();
}
private static void stopTransmission() {
sesion.getTransaction().commit();
sesion.getSessionFactory().getCurrentSession().close();
sesion.clear();
}
ANY IDEAS?
The problem stems from static Session variables. A SessionFactory is thread-safe and, generally speaking, you only need one (static) instance per database. A Session, on the other hand, is not thread-safe and is usually created (using a SessionFactory) and discarted/closed on the fly.
To solve your immediate problem, remove the static Session sesion variable from your Dao and also 'inline' the startTransmission and stopTransmission methods in the findDespachoByTagId method. This will ensure that each thread calling findDespachoByTagId creates and uses its own session instance. To analyze the current problem, imagine two threads calling findDespachoByTagId at the same time. Now the static session variable will be assigned a value twice by the startTransmission method. This means one session instance is lost almost immediatly after it was created while the other one is used by two threads at the same time. Not a good thing.
But there are other problems too: there are no finally blocks that guarantee transactions are closed and database connections are released (via the closing of sessions). Also, you will probably want to use a database pool as the one provided by Hibernate is not suitable for production. I recommend you have a look at HibHik: I created this project to show a minimal stand-alone Java application using Hibernate with a database pool (HikariCP) that uses the recommended patterns and practices (mostly shown in TestDbCrud.java). Use the relevant parts in your application, than write multi-threaded unit-tests to verify your database layer (DAO) is working properly, even in the case of failure (e.g. when the database is suddenly no longer available because the network-cable was unplugged).
I am working in java hibernate and mysql. I want to use transaction settimeout for a payment functionality of application. I just test the code as below for settimeout to work.
Transaction tx = (Transaction) threadTransaction.get();
try {
if (tx == null) {
Session session = (Session) threadSession.get();
session.getTransaction().setTimeout(5);
tx=session.beginTransaction();
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(session.getTransaction().isActive()) {
System.out.println("session active");
}
else {
System.out.println("session inactive");
}
threadTransaction.set(tx);
}
}
catch (HibernateException e) {
throw new HibernateException("", e);
}
But it print session active, means the timeout doesnt work. What is the reason? please help !
Hibernate is pretty good at doing nothing as long as nothing needs to be done (efficiency and such). I think that is what your test shows, not that the the timeout is not working for what it was intended to do:
"... ensuring that database level deadlocks and queries with huge result sets are limited by a defined timeout."
Also note that "setTimeout() cannot be called in a CMT bean ..."
Test the transaction timeout with some code that does what the transaction timeout was intended for and I think you'll find it working properly.
I create only one session factory for the whole progamm and create everytime i want to persist/update/query smth. an new entity manager but i get always an to many connection error. Can anybody give me an adivce? In my point of view it cant be the best solution to increase the number of allowed connections in MySql. I used C3P0 for pooling.
Try using a try-catch-finally template like this whenever calling the EntityManager.
EntityManager em = ... //However you get an em.
try {
em.getTransaction().begin();
// ... Put your persistence code here.
em.getTransaction().commit();
} catch (Exception ex) {
em.getTransaction().rollback();
throw ex;
} finally {
em.close();
}