I have a stored function that will remove something from the database, but since it could be a very long task, I want to make a thread to execute this function, and let the user keep on doing what he is doing.
Currently I have the following:
The DAO:
#Override
#Transactional
public void deleteAll()
{
Session session = (Session) entityManager.getDelegate();
session.doWork(new Work()
{
#Override
public void execute(Connection connection) throws SQLException
{
try
{
// stored function is currently named delete_function()
CallableStatement deleteAll= connection.prepareCall("{call delete_function()}");
purgeArchived.execute();
purgeArchived.close();
}
catch (SQLException exception)
{
LOGGER.warn(exception);
}
}
});
}
Im afraid when i call getDao.deleteAll() in the rest service, this will be in working for a really long time if the database has lot of stuff to delete. How do I create a thread to do the same thing? Or will this create a thread and execute the function?
Yes, you will need to make your own thread for this. Probably the simplest thing to do is to copy the entire body of your current deleteAll() method to the run() method of a new class, that extends Thread. Assuming you've called that class DeleteAllThread, you'd then replace your method above with
#Override
public void deleteAll() {
new DeleteAllThread().start();
}
Another option is to take a look at using a ExecutorService. This may make things a little cleaner for you. Here is a simple example of how to use an ExecutorService.
Related
Hi I have a java program with multiple threads querying an HSQL database. I'm getting some very weird results from the queries and my guess is that the database is not set up to handle many queries at the same time. (Is this even possible in a database?).
What I would like to do then is queue any database queries.
As far as I can tell this is done using the synchronize keyword when making functions in my database object?
My database object looks something like this:
public class Database(){
public Database(){
connect();
}
private void connect(){
//connect to HSQL database
}
public void executeOneTypeOfQuery(){
...
ResultSet rs1 = someStatement.executeQuery();
//do something with a query
}
public void executeAnotherTypeOfQuery(){
...
ResultSet rs2 = anotherStatement.executeQuery();
//do something with a query
}
}
At the moment I may be calling any combination of executeOneTypeOfQuery() and executeAnotherTypeOfQuery() at the same time in different threads.
Should those two functions have the synchronized keyword? Or will that only stop them calling JUST THAT method twice at the same time?
Am I right in thinking another solution could be making use of callbacks (I don't really understand the syntax here)?
So anywhere in my project I call one of those database functions, I call an intermediate synchronized function, stating which database function I really want to use.
So threads call something like:
public synchronized void executeAnyQuery(Function theFunctionIWantToCall, Object[] args){
//do theFunctionIWantToCall
}
Is this the right way to do it? If so what is the syntax with callbacks?
The synchronized keyword locks the function from access by another thread until the function terminates (although it does not guarantee the tread will execute uninterrupted)
For the callback, you would do something like this
public class Foo {
public static void main(String[] args) {
new Foo.doExample();
}
}
I am currently trying to make a hibernate query inside of a TimerTask (Runnable). This task makes no saves or updates to the database. It just retrieves a list of jobs. Anytime I run this task, I get HibernateException: Unable to locate current JTA transaction.
I believe this has to do with the fact that it's being started from a runnable because I use this same query outside of this TimerTask.
I can't share the code I am working with because it is for work and proprietary. My research on this issue has only really led me to solutions with Spring, but I am not able to use Spring for this work.
I will attempt to make some pseudo code.
public class JobManager extends TimerTask {
#Override
public void run() {
...
List<String> jobs = Handler.getJobs();
...
}
}
public class Handler {
public static List<String> getJobs() {
return DAO.getJobs();
}
}
public class DAO {
public List<Object> getJobs() {
try {
session = HibernateManager.getSessionFactory().getCurrentSession();
Query myQuery = session.createQuery("query string");
List = myQuery.list();
} catch(HibernateException he) {
log.error(he);
}
return list;
}
}
The exception occurs when the runnable calls getJobs(). This method work everywhere else outside of the TimerTask.
I understand that this is limited information to work with. I can try to accommodate for any other information if it is needed.
I believe every transaction has some time out, so you can not put the regular timer task code inside the running transaction. As it is just reading the data you wont need to start the transaction, just session is enough
I have encountered the same problem and solved by creating the new session
session = sessionFactory.openSession();
EDIT
session.getCurrentSession() takes the current session from the current thread, so it wont work inside timer task. Use openSession()
Sorry for something that is probably very simple, but I'm new to JPA and I'm not sure where to insert a function call for a method that needs to be called after a new record is committed to a database. I have the following:
#POST
#Override
#Consumes({"application/xml", "application/json"})
#Path("...")
#RolesAllowed("...")
public void create(LearningActivity entity){
super.create(entity);
}
I need to call a custom method myMethod() after the above process is completed. I thought I could add it immediately after super.create(entity) but apparently the commit process isn't completed until the whole create() method executes. I've also tried adding #PostPersist to the underlying entity but that's still before the record is committed.
Any help would be appreciated.
I'm not sure where to insert a function call for a method that needs
to be called after a new record is committed to a database
It sound like you need to use Event Listener, there is an event called PostPersist that is executed every time a entity has been commited to the database, you can configure that using the above code.
#Entity
public class X{
#PostPersist
public void myMethod(){
//Do anything before the commit of the transaction that save a new entity of type X
}
#PostUpdate
public void myMethod2(){
//This code will run each time you update and save an entity of type X
}
}
PostPersist is called after the commit has been completed, PrePersist executes when you call persist method.
Based on this article, #PostPersist is called before commit.
The alternative that I found is to create a static helper method that will call a Runnable after current transaction session is committed.
public static void afterTransactionCommitted(final Runnable function) {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronizationAdapter() {
#Override
public void afterCommit() {
function.run();
}
}
);
} else {
function.run();
}
}
You will use it like
afterTransactionCommitted(() -> myMethod());
I'm trying to speed up our code by calling session.executeAsync() instead of session.execute() for DB writes.
We have use cases where the DB connection might be down, currently the previous execute() throws an exception when the connection is lost (no hosts reachable in the cluster). We can catch these exceptions and retry or save the data somewhere else etc...
With executeAsync(), it doesn't look like there's any way to fulfill this use case - the returned ResultSetFuture object needs to be accessed to check the result, which would defeat the purpose of using the executeAsync() in the first place...
Is there any way to add a listener (or something similar) anywhere for the executeAsync() call that will asynchronously notify some other code that a DB write has failed?
Is this pertinent?
Datastax 1.0.2
Java 1.7.40
You could try something like this since the ResultSetFuture implements ListenableFuture from the Guava library:
ResultSetFuture resultSetFuture = session.executeAsync("SELECT * FROM test.t;");
Futures.addCallback(resultSetFuture, new FutureCallback<ResultSet>() {
#Override
public void onSuccess(#Nullable com.datastax.driver.core.ResultSet resultSet) {
// do nothing
}
#Override
public void onFailure(Throwable throwable) {
System.out.printf("Failed with: %s\n", throwable);
}
});
This approach will not block your application.
You could pass a callback to the method to take action on exception. If you need the ResultSetFuture, you could try something like this:
interface ResultSetFutureHandler {
void handle(ResultSetFuture rs);
}
public void catchException(ResultSetFutureHandler handler) {
ResultSetFuture resultSet = null;
try {
resultSet = getSession().executeAsync(query);
for (Row row : results.getUninterruptibly()) {
// do something
}
} catch (RuntimeException e) {
handler.handle(resultSet); // resultSet may or may not be null
}
}
Then call it like this:
catchException(new ResultSetFutureHandler() {
void handle(ResultSetFuture resultSet) {
// do something with the ResultSetFuture
}
});
If you need to know what the exception was, add an exception parameter too:
interface ResultSetFutureHandler {
void handle(ResultSetFuture rs, RuntimeException e);
}
I have a POJO(Myclass in this example) which I persist/update/delete in my app.
I detect changes to that object using a listener class and then in listener class I save the changes to another table.
Here is my class (dummy example) :
EntityListeners({MyListener.class})
class MyClass {
String name;
String surname;
/*...getters...setter..etc */
public void save() {
JPA.em().persist(this);
return this;
}
public void update() {
JPA.em().merge(this);
}
}
class MyListener {
#preUpdate
public void preUpdate() {
/*...some logic to save the changes irrelevant*/
someAuditObj.createWithData(.......);
someAuditObj.save();
}
}
I'm building my web app using play framework v2.1.3, and all this was working great, I was really happy the way it works.
Today I updated play framework to a newer version v2.2.1.
And the for some reason when instance of MyClass changes and the listener picks up the change and it tries to save the changes the transaction fails and I find this in the log :
Caused by: java.lang.RuntimeException: No EntityManager bound to this thread
So it took me a while to figure out that for some reason transaction is not propagated to listener and then I tried something to fix it (Listener class):
#preUpdate
public void preUpdate() {
/*...some logic to save the changes irrelevant*/
JPA.withTransaction(new F.Callback0() {
#Override
public void invoke() throws Throwable {
someAuditObj.createWithData(.......);
someAuditObj.save();
});
}
So this fixes it, and it works like before without issues.
My question(s) is :
Why did it work before without meddling manually with transactions with earlier version of play framework
Is there a better way of achieving the same thing more elegantly (I'm not sure that is the right word for it)?
Update
This is my controller method :
#Transactional
public Result updateName(Long id, String name){
MyClass c = MyClass.findById(id);
c.setName(name);
c.update();
return ok();
}
So transaction should be propagated to all methods right? but why not to listener as well?
My estimate was this :
if a method has #Transactional annotation then all calls that happens inside should be in a transaction?
Seems that you got same problem as mine. Look at my issue: https://github.com/playframework/playframework/issues/2042
Same JPA code works with 2.1.0 but not working with 2.2.1
So i think it's a bug.
Why did it work before without meddling manually with transactions
with earlier version of play framework
Is there a better way of
achieving the same thing more elegantly (I'm not sure that is the
right word for it)?
We have just to wait till this issue will solved or wait some explanation about using threads with JPA transaction from play2 developers in this issue. At this moment issue is open.
In our view, the problem is that JPA.withTransaction() (and #Transactional uses this too) blocks cannot be nested since .withTransaction() unbinds the em unconditionally, and if its an inner .withTransaction(), the outer block will be left without a bound em.
So this test fails at c.save() (save persists the entity in our case)
#Test
public void nestedJPACalls() {
JPATestEntity a = new JPATestEntity();
JPATestEntity b = new JPATestEntity();
JPATestEntity c = new JPATestEntity();
JPA.withTransaction(() -> {
a.save();
JPA.withTransaction(() -> {
b.save();
});
c.save();
});
}
The .withTransaction() methods should check if the em is already bound, and if so, neither bind nor unbind it. I've added that to the discussion at https://github.com/playframework/playframework/issues/2042
We're working on a clean solution now. A temporary but ugly solution is to just try/catch and run your code inside JPA.withTransaction() only if you get the "No EntityManager bound to this thread" exception.
// Create receipt asynch
Akka.future(new Callable() {
public Object call() {
// Issue Receipt
JPA.withTransaction(new F.Callback0() {
#Override
public void invoke() throws Throwable {
// TODO Auto-generated method stub
issueReceipt(pgTxn); // test
}
});
return null;
}
});