Spring DatasourceTransaction Manager Problem - java

final DataSource ds = DataSourceLocator.getInstance()
.getDataSource(sg.cmpl.starhub.lprs.Constants.APP_KEY);
final DataSourceTransactionManager txManager = new DataSourceTransactionManager();
txManager.setDataSource(ds);
final DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
final TransactionStatus status = txManager.getTransaction(def);
Connection conn = null;
PreparedStatement ps = null;
try {
/***************************************************************************/
conn = DataSourceUtils.getConnection(ds);
ps = conn.prepareStatement(sql);
ps.execute();
/***************************************************************************/
txManager.commit(status);
} catch (Exception e) {
txManager.rollback(status);
}
Is there something wrong with my transaction manager logic? It looks like unstable. When I insert new data, First time it seems to save and later I can't find the data in mysql database. Please help. Thanks a lot.

Assuming there's a special reason you want to do programmatic connection and transaction management I suggest taking a look at Spring's JdbcTemplate and wrap it's usage in a TransactionTemplate.
However as stated in the previous comment, you should try to avoid programmatic transaction management as much as possible and use annotations (#Transactional) or XML configuration (TransactionProxyFactoryBean or <tx:advice/>) instead.

Yes, there is something wrong. This is not the Spring way. You should not be putting commit/rollback logic in code like this. The advantage comes when you can do it declaratively, in configuration.
Have a look at the Spring transaction reference docs.

As a side note: according to Spring documentation if commit operation fails with TransactionException then rollback was already called and calling it again in catch block will trigger IllegalTransactionStateException.

Related

Using DataSource with Transaction using Spring

I am working as part of a legacy j2ee application (plain application no Spring or Hibernate support)
The application exposes the following method:
public DataSource getConnectionDataSource();
DataSource is properly initiated to a specific DB schema by the product.
When I want to query the DB I create a jdbcTemplate object and query the like so:
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("PRINT_LOCA",printerLocation);
DataSource printersSchemaDS = context.getCommonServices().getConnectionDataSource("printersSchema");
NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(printersSchemaDS);
String printerId = jdbcTemplate.queryForObject("select printerId from printers where printer_location=:PRINT_LOCA ",parameters,String.class);
My question is how can I execute multiple Update SQL statements in a single transaction when I only have the DataSource object?
I see that there is TransactionTemplate in Spring, but is it possible to initialize it with DataSource object alone?
Thank you!
Try to take single connection from datasource, then use ordinary manual jdbc transaction:
try (Connection con = datasource.getConnection();) {
con.setAutoCommit(false);
// insert logic
con.commit();
} catch (SQLException e) {
// handle exception
con.rollback();
}
Full example here:
https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html

How to call multiple DAO functions in a transaction

I'm looking for a way to call multiple DAO functions in a transaction but I am NOT using spring or any such framework. What we actually have is a Database api type .jar which gets initialized with the used datasource. What I want to achieve is have my business logic level code do something like:
Connection conn = datasource.getConnection();
conn.setAutoCommit(false);
DAOObject1.query1(params, conn);
DAOObject2.query4(params, conn);
conn.commit();
conn.setAutoCommit(false);
however I want to avoid passing the connection object in every single function since this is not the correct way to do it. Right now in the few transactions we have we use this but we are looking for a way to stop passing the connection object to the database layer or even create it outside of it. I'm looking for something along the lines of:
//Pseudocode
try{
Datasource.startTransactionLogic();
DAO1.query(params);
DAO2.query(params);
Datasource.endAndCommitTransactionLogic();
}
catch(SQLException e){
Datasource.rollbackTransaction();
}
Could I achieve this through EJBs? Right now we're not using DAOs through injection, we're creating them by hand but we're about to migrate to EJBs and start using them via the container. I've heard that all queries executed by EJBs are transactional but how does it know what to rollback to? Through savepoints?
EDIT:
Let me point out that each DAO object's method, right now, obtains its own connection object. Here is an example of how our DAO classes will be:
public class DAO {
public DTO exampleQueryMethod(Integer id) {
DTO object = null;
String sql = "SELECT * FROM TABLE_1 WHERE ID = ?";
try (
Connection connection = datasourceObject.getConnection();
PreparedStatement statement = connection.prepareStatement(sql)
) {
statement.setInt(1, id);
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
object = DAO.map(resultSet);
}
}
}
return object;
}
}
Right now what we're doing for methods that need to be in a transaction is to have a second copy of them that receive a Connection object:
public void exampleUpdateMethod(DTO object, Connection connection) {
//table update logic
}
What we want is to avoid having such methods in our 'database api' .jar but instead be able to define the beginning and commit of a transaction in our business logic layer, like mentioned in the pseudocode above.
What i have done in the past is to create a Repository Object that takes the Database API and generates a connection and saves the connection as a member variable to it. (along with the database reference as well)
I then hang all the Business Layer calls as methods from this Repository Object for convenience to the caller.
This way.. you can call, mix, match any calls and use the underlying connection, perform rollback, commits.. etc.
Repository myr = new Repository(datasource); // let constructor create connection
myr.setAutoCommit(false);
myr.DAOObject1(parms); // method wrapper
myr.DAOObject2(parms); // method wrapper
myr.commitwork(); // method in Repository that calles endAndCommitTransactionLogic
We then took this new object, and created a pool of them primed, and managed in a new thread, and the Application just requested a new "Repository" from the pool.. and off we went.
#JBNizet comment was correct, but ... please think twice whether you really need to migrate to the EJBs. Even transactions are not much intuitive there: wrapping your exception into javax.ejb.EJBException isn't neither flexible nor readable. Not to mention other problems, like startup time or integration testing.
Judging from your question, it seems that all you need is a Dependency Injection framework with support for the Interceptors. So possible ways to go:
Spring is definitely the most popular in this area
CDI (Weld or OpenWebBeans) which came since Java EE 6 release - but can used totally without Java EE Application Server (I'm using this approach right now - and it works nicely).
Guice also comes with its own com.google.inject.persist.Transactional annotation.
All three above frameworks are equally good for your use case, but there are other factors that should be considered, like:
which one you & your team is familiar with
learning curve
your application's future possible needs
framework's community size
framework's current development speed
etc.
Hope it helps you a little bit.
EDIT: to clarify your doubts:
You can create your own Transaction class, which would wrap a Connection fetched from the datasource.getConnection(). Such transaction should be a #RequestScoped CDI bean and contain method methods like begin(), commit(), and rollback() - which would call connection.commit/ rollback under the hood. Then you can write a simple interceptor like this one which would use mentioned transaction and start/ commit/ rollback it wherever needed (of course with AutoCommit disabled).
It is doable, but keep in mind, that it should be carefully designed. That is why interceptors for transactions have been already provided in almost every DI platform/ framework.
EDIT:
After accumulating a few more years of experience, I'd like to point out that the simplest and most correct answer to this question was to use ThreadLocal objects to contain the Connection (since it's request scoped only a single threads executes it). Unfortunately at the time I didn't know the existence of such a construct.
#G. Demecki has the right idea but I followed a different implementation. Interceptors couldn't solve the problem (at least from what I saw) because they need to be attached to each function that is supposed to use them. Also once an interceptor is attached, calling the function will always have it intercepted which is not my goal. I wanted to be able to explicitly define the beginning and ending of a transaction, and have every sql executed between these 2 statements be part of the SAME transaction, without it having access to the database's related objects (like connection, transaction etc) through argument passing. The way I was able to achieve this (and quite elegant in my opinion) is the following:
I created a ConnectionWrapper object like so:
#RequestScoped
public class ConnectionWrapper {
#Resource(lookup = "java:/MyDBName")
private DataSource dataSource;
private Connection connection;
#PostConstruct
public void init() throws SQLException {
this.connection = dataSource.getConnection();
}
#PreDestroy
public void destroy() throws SQLException {
this.connection.close();
}
public void begin() throws SQLException {
this.connection.setAutoCommit(false);
}
public void commit() throws SQLException {
this.connection.commit();
this.connection.setAutoCommit(true);
}
public void rollback() throws SQLException {
this.connection.rollback();
this.connection.setAutoCommit(true);
}
public Connection getConnection() {
return connection;
}
}
My DAO objects themselves follow this pattern:
#RequestScoped
public class DAOObject implements Serializable {
private Logger LOG = Logger.getLogger(getClass().getName());
#Inject
private ConnectionWrapper wrapper;
private Connection connection;
#PostConstruct
public void init() {
connection = wrapper.getConnection();
}
public void query(DTOObject dto) throws SQLException {
String sql = "INSERT INTO DTO_TABLE VALUES (?)";
try (PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setString(1, dto.getName());
statement.executeUpdate();
}
}
}
Now I can easily have a jax-rs resource which #Injects these objects and starts and commits a transaction, without having to pass any Connection or UserTransaction around.
#Path("test")
#RequestScoped
public class TestResource {
#Inject
ConnectionWrapper wrapper;
#Inject
DAOObject dao;
#Inject
DAOObject2 dao2;
#GET
#Produces(MediaType.TEXT_PLAIN)
public Response testMethod() throws Exception {
try {
wrapper.begin();
DTOObject dto = new DTOObject();
dto.setName("Name_1");
dao.query(dto);
DTOObject2 dto2 = new DTOObject2();
dto2.setName("Name_2");
dao2.query2(dto2);
wrapper.commit();
} catch (SQLException e) {
wrapper.rollback();
}
return Response.ok("ALL OK").build();
}
}
And everything works perfectly. No Interceptors or looking around InvocationContext etc.
There are only 2 things bothering me:
I have not yet found a way to have a dynamic JNDI name on #Resource(lookup = "java:/MyDBName") and this bothers me. In our AppServer we have defined many datasources and the one used by the application is dynamically chosen according to an .xml resource file packaged with the war. Which means that I can't know the datasource JNDI on compile time. There is the solution of obtaining a datasource through InitialContext() environment variable but I'd love to be able to get it as a resource from the server. I could also create a #Produces producer and inject it that way but still.
I'm not really sure why ConnectionWrapper's #PostConstruct gets called BEFORE the DAOObject's #PostConstruct. It is the correct and desired behavior but I haven't understood why. I'm guessing since DAOObject #Injects a ConnectionWrapper, its #PostConstruct takes precedence since it has to have finished before the DAOObjects's can even start but this is just a guess.

Disabling auto-commit in NamedParameterJdbcTemplate.batchUpdate

I am doing a batch update into my DB table using NamedParameterJdbcTemplate.batchUpdate, but I would like to disable auto-commit and perform the commit manually.
I can set auto-commit mode off from the connection object, but not sure how to do the same using NamedParameterJdbcTemplate object.
I have done my implementation using TransactionTemplate
It has an execute method and I do the business logic inside a callback in this function.
transTemplate.execute( new TransactionCallbackWithoutResult()
{
#Override
protected void doInTransactionWithoutResult( TransactionStatus status)
{
status.setRollbackOnly();
//business logic
}
});
I assume you are aware of the transactional management in Spring where by defining #Transactional and passing metadata of Propagation and Isolation you can elegantly manage transactions. If not take a look at the Spring documentation. In most cases that's all you need.
If you want to get transaction management at your own hands and fine-tune it (aka perform commit and rollbacks at will) you have to get the underlying TransactionManager directly.
Quoting from the Spring docs:
Using the PlatformTransactionManager
You can also use the org.springframework.transaction.PlatformTransactionManager directly to manage your transaction. Simply pass the implementation of the PlatformTransactionManager you are using to your bean through a bean reference. Then, using the TransactionDefinition and TransactionStatus objects you can initiate transactions, roll back, and commit.
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// explicitly setting the transaction name is something that can only be done programmatically
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
// execute your business logic here
}
catch (MyException ex) {
txManager.rollback(status);
throw ex;
}
txManager.commit(status);

How to get current Connection object in Spring JDBC

How can I get the current Connection object for an Oracle database? I'm using the JDBC module in Spring 3.0.5.
Obtain the Connection from the DataSource bean.
You can access the dataSource by using Spring dependency injection to inject it into your bean, or by accessing ApplicationContext statically:
DataSource ds = (DataSource)ApplicationContextProvider.getApplicationContext().getBean("dataSource");
Connection c = ds.getConnection();
Just an Info :
I am using Spring JDBC Template, which holds the current connection object for me, which can be received as follows.
Connection con;
con = getJdbcTemplate().getDataSource().getConnection();
Use DataSourceUtils.getConnection().
It returns connection associated with the current transaction, if any.
I'm not sure if this method was available when this question was originally posted, however, it seems the preferred way to do it in the latest version of Spring is with JdbcTemplate and PreparedStatementCreator. See https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcTemplate.html#query-org.springframework.jdbc.core.PreparedStatementCreator-org.springframework.jdbc.core.PreparedStatementSetter-org.springframework.jdbc.core.ResultSetExtractor- or any of the other query methods that take a PreparedStatementCreator as the first param:
jdbcTemplate.query(con -> {
// add required logic here
return con.prepareStatement("sql");
}, rs -> {
//process row
});
This has the advantage over the other provided answers (DataSourceUtils.getConnection() or jdbcTemplate.getDataSource().getConnection() as a new connection is not allocated, it uses the same connection management it would as calling any of the other jdbcTemplate querying methods. You also therefore do not need to worry about closing / releasing the connection, since spring will handle it.

Hibernate template close transaction

I run following working code:
Session session = null;
try {
SessionFactory sessionFactory = new Configuration().configure()
.buildSessionFactory();
session = sessionFactory.openSession();
String id = (String) FacesContext.getCurrentInstance()
.getExternalContext().getRequestParameterMap().get(
"storeId");
Transaction t = session.beginTransaction();
stores = getStores();
for (Store store : stores) {
if (store.getId() == Integer.parseInt(id)) {
session.delete(store);
}
}
t.commit();
} catch (Exception e) {
} finally {
session.close();
}
}
When i try redo this code to use Hibernate template, i go unending request to DB:
HibernateTemplate template = new HibernateTemplate();
template .setSessionFactory(sessionFactory);
stores = template.find("from Stores");
for (Store store : stores) {
if (store.getId() == Integer.parseInt(id)) {
template.delete(store);
}}
Looks like transaction is not closed.
How could I close transaction this case? And is it will better at all to use Hibernate template approach instead of session approach showed at first code?
You didn't say it, but I assume you're referring to the HibernateTemplate class in the Spring Framework. HibernateTemplate participates in Spring transactions, but it doesn't manage them on its own. Spring provides a lot of ways to manage transactions both programmatically and declaratively. If you're just experimenting, you can use the TransactionTemplate class to quickly test it out. For larger projects, you should consider using declarative transaction management because it simplifies your code, although it's a little trickier to set up initially.
As for whether or not the HibernateTemplate approach is better than managing your sessions manually, I'd say anything that reduces boilerplate code is a good thing, so yes. This is especially crucial on big projects. However, depending on your project, HibernateTemplate might not even be necessary. It was originally created to work around some deficiencies in Hibernate 2.x, but many of those deficiencies were eliminated in Hibernate 3. So before adopting it, read the HibernateTemplate JavaDoc for a discussion of the advantages.

Categories

Resources