I'm using EclipseLink as my JPA provider.
When I use the following code on a query object:
myQuery.setHint("eclipselink.read-only", "true");
The query is executed on a different connection than the original EntityManager is using and return wrong results.
Does it make sense that setting the query to read only will cause EclipseLink to run it on a different connection? (I'm using connection pooling).
In additional I've added in the persistence.xml:
<shared-cache-mode>NONE</shared-cache-mode>
to disable cross session cache.
Read-only queries are meant to only show read-committed data. If you want transactional data, you should not use read-only.
You may be able to use an exclusive connection, (persistence unit, or persistence context property)
"eclipselink.jdbc.exclusive-connection.mode"="Always"
Related
I came across an old project using OpenJPA with DB2 running on Websphere Liberty 18. In the persistence.xml file there is a persistent unit with the following declaration:
<persistence-unit name="my-pu" transaction-type="RESOURCE_LOCAL">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<jta-data-source>jdbc/my-data-source</jta-data-source>
</persistence-unit>
In the case that we are using RESOURCE_LOCAL transactions and there is code to manually manage the transactions scattered throughout the whole application, shouldn't the data source be declared as "non-jta-data-source"? Interestingly it seems the application is working fine despite that. Any ideas why it works fine?
<non-jta-data-source> specifies a data source that refuses to enlist in JTA transactions. This means, if you do userTransaction.begin (or take advantage of any API by which the container starts a transaction for you), and you perform some operations on the data source (which is marked with transactional="false" in Liberty) those operations will not be part of the encompassing JTA transaction and can be committed or rolled back independently. It's definitely an advanced pattern, and if you don't know what you are doing, or temporarily forget that the data source doesn't enlist, you can end up writing code that corrupts your data. At this point, you may be wondering why JPA even has such an option. I expect it isn't intended for the end user's usage of JPA programming model at all, but is really for the JPA persistence provider (Hibernate/EclipseLink/OpenJPA) implementation. For example, if you consider the scenario where a JTA transaction is active on the thread and you perform an operation via JPA where the JPA persistence provider needs to generate a unique key for you, and the persistence provider needs to run some database command to reserve the next block of unique keys, the JPA persistence provider can't just do that within your transaction because you might end up rolling it back, and then the same block of unique keys could be given out twice and errors would occur. The JPA persistence provider really needs to suspend your transaction, run its own transaction, and then resume yours. In my opinion suspend/resume would have been the natural solution here, but the JTA spec doesn't provide a standard way to obtain the TransactionManager, and so my guess is that the JPA spec invented its own solution for situations like this of requiring a data source that bypasses transaction enlistment as an alternative. A JPA provider can run its own transactional operations on the non-jta-data-source while your JTA transaction continues on unimpacted by it. You'll also notice with the example I chose, that it doesn't apply to a number of paths through JPA. If your JPA entity is configured to have the database generate the unique keys instead, then the persistence provider doesn't need to perform its own database operations on a non-jta-data-source. If you aren't using JTA transactions, then the persistence provider doesn't need to worry about enlisting in your transaction because it can just use a different connection, so it doesn't need a non-jta-data-source there either.
I am currently developing a Spring Boot app, which uses mybatis for its persistence layer. I want to optimize the batch insertion of entities in the following scenario:
// flightSerieMapper and legMapper are used to create a series of flights.
// legMapper needs to use batch insertion.
#Transactional
public FlightSerie add(FlightSerie flightSerie) {
Integer flightSerieId = flightSeriesSequenceGenerator.getNext();
flightSerie.setFlightSerieId(flightSerieId);
flightSerieMapper.create(flightSerie);
// create legs in batch mode
for (Leg leg : flightSerie.getFlightLegs()) {
Integer flightLegId = flightLegsSequenceGenerator.getNext();
leg.setLegId(flightLegId);
legMapper.create(leg);
}
return flightSerie;
}
mybatis is configured as follows in application.properties:
# this can be externalized if necessary
mybatis.config-location=classpath:mybatis-config.xml
mybatis.executor-type=BATCH
This means that mybatis will execute all statements in batch mode by default, including single insert/update/delete statements. Is this OK? Are there any issues I should be aware of?
Another approach would be to use a dedicated SQLSession specifically for the LegMapper. Which approach is the best (dedicated SQLSession vs global setting in application.properties)?
Note: I have seen other examples where "batch inserts" are created using a <foreach/> loop directly in the mybatis xml mapper file. I don't want to use this approach because it does not actually provide a batch insert.
As #Ian Lim said, make sure you annotate mapper methods with inserts and updates with #Flush annotation if you globally set executor type to BATCH.
Another approach would be to use a dedicated SQLSession specifically
for the LegMapper. Which approach is the best (dedicated SQLSession vs
global setting in application.properties)?
Keep in mind that if you are using different SQL sessions for different mappers there will be different transactions for each SQL session. If a service or service method annotated with #Transactional uses several mappers that use different SQL sessions it will allocate different SQL transactions. So it's impossible to do atomic data operation that involves mappers with different SQL sessions.
using EclipseLink as JPA 2.0 provider, I can obtain a JDBC connection by simply calling
Connection con = entityManager.unwrap(Connection.class);
But I'm unsure what I'm responsible for. Do I have to close the connection after submitting my queries? Or are I'm not allowed to close the connection, because EclipseLink also uses this connection internally. Or does it not care, because EclipseLink observes my behaviour and closes the connection automatically if I don't do it?
If you are in the context of a JPA transaction the connection will be managed by the provider (EclipseLink). If you are outside of a transaction you are responsible for managing the connection yourself.
See the following link for additional information:
http://wiki.eclipse.org/EclipseLink/Examples/JPA/EMAPI#Getting_a_JDBC_Connection_from_an_EntityManager
But I'm unsure what I'm responsible for. Do I have to close the
connection after submitting my queries? Or are I'm not allowed to
close the connection, because EclipseLink also uses this connection
internally.
A good and valid question. It seems that the documentation is lacking the semantics of the unwrap() calls.
Regarding EclipseLink, according from what I got from the source:
EclipseLink gives you a reference to the currently active connection which it uses for the currently active client session transaction. If no transaction is active, a new will be created, associated with the session and returned from the unwrap() method.
As a result, IMHO, a commit/rollback of such a obtained Connection may lead to undefined behavior and/or exceptions. Same is true for executing DML which changed records have been previously cached by eclipselink internal caches or for which managed entities exist.
So when using this API, especially if the underlying transaction is dirty, be careful.
If you can refer to internal eclipselink classes, you can access eclipselink internal connection pool to get a Connection exclusively (have a look at org.eclipse.persistence.sessions.server.ServerSession.getConnectionPool(String) ).
I want to manage the database connection outside entity manager context so that I can use it for different entity managers. The question is how can I build the entity manager factory or entity manager with my own connection instead of providing it with properties in persistence.xml?
In either case the answer is that you cannot, in SE you can specify the db connection properties when creating the EntityManagerFactory, but the db connection is still maintained by the EntityManager and for good reason, if you controlled this you could commit and rollback behind the EntityManager's back. If you gave the same db connection to multiple EntityManager's this would be chaos indeed, I am not sure why on earth you want to do this.
The best I can suggest is that you look into the EntityManager.getDelegate() (JPA 1.0) or EntityManager.unwrap(java.lang.Class cls) (JPA 2.0) methods they may return the underlying provider (ie. Hibernate) object which you may be able to pry the database connection out of, but you certainly won't be able to replace it.
In short really bad idea.
Is it possible to use EJB 3 with JDBC. I read somewhere, that it's allowed.
However, I hear that EJB 3 implementation uses JTA, by default. What does that mean for JDBC? Is it only for the transaction support? That means JTA is used for transaction when using JDBC code? Meaning that even local transactions are implemented as global transactions?
Does it mean it's not a good idea to use JDBC with EJB 3? Many people point me to JPA, but it's an ORM. I want to use SQL.
any suggestions?
1º
That means JTA is used for transaction when using JDBC code ?
And
Meaning that even local transactions are implemented as global transactions ?
The EJB container CAN MAKE USE of resource manager local transactions AS AN OPTIMIZATION TECHNIQUE for enterprise beans for which distributed transactions ARE NOT NEEDED.
It is a good idea do the following when using a declarative or programmatic transaction demarcation:
declare resources using the Resource annotation in the enterprise bean class or using the resource-ref element in the enterprise bean’s deployment descriptor
Something like (setter method or member field)
// mappedName points to a global mapping name
#Resource(mappedName="java:/DefaultDS")
private javax.sql.DataSource ds;
And inside a business logic method
If you are using a declarative transaction
Connection conn = ds.getConnection();
If you are using a programmatic transaction
Declare a setter or member field UserTransaction
#Resource
private UserTransaction ut;
And
ut.beginTransaction();
Connection conn = ds.getConnection();
ut.commit();
Take care of the following
If you are using a Stateful session bean, do the following in the PrePassivate callback method
Close all JDBC connections in the PrePassivate method and assign the instance’s fields storing the connections to null
regards,
You can look at this page, it does appear that you can combine EJB3 with JDBC.
http://www.java2s.com/Tutorial/Java/0415__EJB3/UseJDBCInEJB.htm
If you are using JPA2, you can use entityManager.unwrap(Connection.class) to get actual connection and use with your JDBC code.
For example:
Connection connection = entityManager.unwrap( Connection.class );
try (Statement stmt = connection.createStatement()) {
stmt.executeUpdate( "INSERT INTO MyTable( name ) VALUES ( 'my name' ) " );
}
Does it mean it's not a good idea to use JDBC with EJB 3? Many people
point me to JPA, but it's an ORM. I want to use SQL.
Sometime it's necessary, for performance or compatibility issues. I usually use this technique to execute PL/PSQL with array parameters, complex Posgis SQL, etc.