简体   繁体   中英

JSON mapping problem: possible non-threadsafe access to the session

I am facing a problem due which is unknown to me, can you one have faced this problem?

JSON mapping problem: <package>ApiResponse["data"]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: possible non-threadsafe access to the session (through reference chain: <package>.ApiResponse["data"])

I have a standard API response pojo. Which I return every time with ResponseEntity. Everything is working fine, but sometimes I got that above error. I don't why this error occurred.

I got the below log from console

an assertion failure occurred (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: possible non-threadsafe access to the session

org.hibernate.AssertionFailure: possible non-threadsafe access to the session

I think you are trying to share same Hibernate session within multiple threads. That's illegal.

Hibernate Sessions are not thread-safe whereas Hibernate SessionFactory is thread-safe.

So, make a separate DAO layer. Create single sessionfactory object and share it among the DAO classes.

Get a session for a single-threaded DB operation and close the session in that thread.

For example:

@Repository
public class DAO {

    @Autowired
    private SessionFactory sessionFactory;

    public class performDBOperation(Object obj) {
      Session session = sessionFactory.currentSession();
      session.save(obj);
      session.close(); 
    }

}

Now, I have looked at your github code.

I saw the code Exec.java

@Service
public interface Exec {

    @Async
    @Transactional
    public void run();
}

This is incorrect.

Updated:

public interface Exec {

    public void run();
}

Update ExecImpl to this:

@Service
public class ExecImpl implements Exec {

    @Autowired
    private ExecDAO execDAO;

    @Override
    @Async
    @Transactional
    public void run() {
       // example : create an object to save it.
       Object object = ...; 
       execDAO.saveItem(object);
    }
}

Create DAO layer:

Suppose ExecDAO interface and implementation ExecDAOImpl :

 public interface ExecDAO {

        public void saveItem(Object obj);

        // keep here abstract method to perform DB operation 
 }

    @Repository
    public class ExecDAOImpl implements ExecDAO {

        @Autowired
        private SessionFactory sessionFactory;

        @Override
        public void saveItem(Object obj) {
          Session session = sessionFactory.currentSession();
          session.save(obj);
          session.close(); 
        }
    }

Looking at the code at the link you shared in the comment, I think that

@Async
@Transactional

is a dangerous thing. I would suggest you to extract a method to do the transactions and try what I mean is that,

interface ExecImpl{
  @Async
  void run(){
     someThingElse.doTransaction();
  }
}

interface SomeThingElse{
  @Transactional
  void doTransaction();
}

I am still not convinced this will help you. But this is something you can try.

I would also suggest to use readonly transactions for getting data and not have a single transaction for all purposes.

This blog explains why its not good to use these two annotations together whether on a class or on an interface

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM