I am working on an application that uses Oracle's built in authentication mechanisms to manage user accounts and passwords. The application also uses row level security. Basically every user that registers through the application gets an Oracle username and password instead of the typical entry in a "USERS" table. The users also receive labels on certain tables. This type of functionality requires that the execution of DML and DDL statements be combined in many instances, but this poses a problem because the DDL statements perform implicit commits. If an error occurs after a DDL statement has executed, the transaction management will not roll everything back. For example, when a new user registers with the system the following might take place:
Start transaction
Insert person details into a table. (i.e. first name, last name, etc.) -DML
Create an oracle account (create user testuser identified by password;) -DDL implicit commit. Transaction ends.
New transaction begins.
Perform more DML statments (inserts,updates,etc).
Error occurs, transaction only rolls back to step 4.
I understand that the above logic is working as designed, but I'm finding it difficult to unit test this type of functionality and manage it in data access layer. I have had the database go down or errors occur during the unit tests that caused the test schema to be contaminated with test data that should have been rolled back. It's easy enough to wipe the test schema when this happens, but I'm worried about database failures in a production environment. I'm looking for strategies to manage this.
This is a Java/Spring application. Spring is providing the transaction management.
First off I have to say: bad idea doing it this way. For two reasons:
Connections are based on user. That means you largely lose the benefits of connection pooling. It also doesn't scale terribly well. If you have 10,000 users on at once, you're going to be continually opening and closing hard connections (rather than soft connection pools); and
As you've discovered, creating and removing users is DDL not DML and thus you lose "transactionality".
Not sure why you've chosen to do it this but I would strongly recommend you implement users at the application and not the database layer.
As for how to solve your problem, basically you can't. Same as if you were creating a table or an index in the middle of your sequence.
You should use Oracle proxy authentication in combination with row level security.
Read this: http://www.oracle.com/technology/pub/articles/dikmans-toplink-security.html
I'll disagree with some of the previous comments and say that there are a lot of advantages to using the built-in Oracle account security. If you have to augment this with some sort of shadow table of users with additional information, how about wrapping the Oracle account creation in a separate package that is declared PRAGMA AUTONOMOUS_TRANSACTION and returns a sucess/failure status to the package that is doing the insert into the shadow table? I believe this would isolate the Oracle account creation from the transaction.
Related
I would like to save in my database information about history, for example user "dog" edited field "grass" in table "garden".
I have trigger which saves everything correctly but I have problem with username "dog". Username is logged user's name and I don't now how to "catch" it, because I don't know how to tell my database (PostgreSQL) that this specific user did that.
How can I tell my trigger that it should use value "dog"?
I would like to write an application in Java using Spring Framework and Hibernate Framework. I haven't any app code, because now I'm creating database and thinking about my future application.
Any ideas?
For certain database platforms, they offer context parameters. To use these, you would:
Set the database context parameters.
You can simply use the native SQL interface exposed by Session or EntityManager to accomplish this step.
Register an AfterTransactionCompletionProcess with the Session.
This should basically use the provided Session and clear the database context parameters which you set as part of (1). You would want to do this regardless of whether the transaction was successful or not. This step makes sure those context parameters are cleared prior to giving the JDBC connection back to your connection pool.
Execute your normal ORM changes.
But there is probably a much simplier approach all together, called Hibernate Envers.
Hibernate Envers is designed to mirror your mapped #Entity classes and keep a running history of changes made to your entities. You can easily configure the fields you'd like audited should there only be a subset of fields you're interested in the history on. Additionally, the Envers API exposes an easy way for you to query the history tables and get historical snapshots.
In order to store your username "dog" with Hibernate Envers, you would need to merely implement a custom RevisionEntity that contains your userName field and set it. You can find more information on how to configure the necessary components for this here.
I'm running an integration test that executes some Hibernate code within a single transaction (managed by Spring). The test is failing with a duplicate key violation and I'd like to hit a breakpoint just before this and inspect the table contents. I can't just go into MySQL Workbench and run a SELECT query as it would be outside the transaction. Is there another way?
After reading your comments, my impression that predominantly you are interested in how to hit a breakpoint and at the same time be able to examine database contents. Under normal circumstances I would just offer you to log the SQLs. Having the breakpoint in mind my suggestion is:
Reduce isolation level to READ_UNCOMMITED for the integration test.
Reducing the isolation level will allow you to see the uncommitted values in the database during the debugging. As long as you don't have parallel activity within the integration test. It should be fine.
Isolation level can be set up on per connection basis. There is no need for anything to be done on the server.
One side note. If you are using Hibernate even the parallel activities may work fine when you reduce the ISOLATION LEVEL because largely Hibernate behaves as it is in REPEATABLE_READ because of the transactional Level 1 cache.
The following can be run from Eclipse's "Display" view:
java.util.Arrays.deepToString(
em.createNativeQuery("SELECT mystuff FROM mytable").getResultList().toArray())
.replace("], ", "]\n");
This displays all the data, albeit not in a very user-friendly way - e.g. will need to work out which columns the comma-separated fields correspond to.
I'm not getting a clear idea of why autocommit is by default false in Hibernate when we have the Transaction management apis provided.
I have three questions
why autocommit mode is not recommended by Hibernate?
What happens when we use autocommit = true and then use the Hibernate Transaction apis for transaction management ?
When using spring declarative transaction management how #Transactional(readonly = true) will help the read only code (Hibernate code) we write?
I will answer one by one Starting with (2) as i don't know much about (1)
(2): autocommit=true means by default all queries get commited. In such case If
if there is a #Transactional on a method, it overrides the autocommit and encloses all queries into a single transaction, thus overriding the autocommit
if there is a #Transactional method that calls other #Transactional annotated methods, the outer most annotation should override the inner annotaions and create a larger transaction, thus annotations also override eachother.
(3): In DBs like Oracal/Mysql a read only transaction can be translated READ_ONLY level which provides no dirty reads, no unrepeatable reads but doesn’t allow any updates. That means the flush mode will be set as FlushMode.NEVER in the current Hibernate Session preventing the session from commiting the transaction. Even setReadOnly(true) will be called on the JDBC Connection which ensure that you cannot call session.flsuh() even to flush session manually.
since Spring doesn't do persistence itself, it cannot specify what readOnly should exactly mean. This attribute is only a hint to the provider, the behavior depends on, in this case, Hibernate.
In regards of (1):
Suppose, you own a company and have 1000 employees. You maintain a database table to track if an employee was paid at the end of the month already or not.
So, here we are, the end of the month and pay day. Payroll sends you an excel file
with 600 names who has just received their compensation for the last month. So you log on to your computer and start your java app and select the excel to save all 600 records in your database. It usually takes 2 minutes, but now it fails at 1 minute and 23 second. What is your expectation now? Do you expect a partially uploaded file with gosh'knows how many records, or nothing at all? Your autocommit will drive it: If autocommit=false then you can give a go to upload the whole file again and again, but if autocommit=true you might need to tweak around your input data first to remove some records to prevent duplicates in your database.
I hope, my simplified example helps you to better understand it, but really the purpose is to ensure either everything from a batch is saved (it includes every write operation, like insert/update/delete) in the database or nothing at all in case an error occurs at anytime during the process. In the real life in most of the cases you and your organisation will expect complete data sets rather than partial data set in the database. Understanding it is key and anybody who advises to 'use autocommit=true because it is safe' should be avoided by miles. This is a key concept and one of the foundation of data management.
We have a somewhat huge application which started a decade ago and is still under active development. So some parts are still in J2EE 1.4 architecture, others using Java EE 5/6.
While testing some new code, I realized that I had data inconsistency between information coming in through old and new code parts, where the old one uses the Hibernate session directly and the new one an injected EntityManager. This led to the problem, that one part couldn't see new data from the other part and thus also created a database record, resulting in primary key constraint violation.
It is planned to migrate the old code completely to get rid of J2EE, but in the meantime - what can I do to coordinate database access between the two parts? And shouldn't at some point within the application server both ways come together in the Hibernate layer, regardless if accessed via JPA or directly?
You can mix both Hibernate Session and Entity Manager in the same application without any problem. The EntityManagerImpl simply delegates calls the a private SessionImpl instance.
What you describe is a Transaction configuration anomaly. Every database transaction runs in isolation (unless you use REAN_UNCOMMITED which I guess it's not the case), but once you commit it the changes are available from any other transaction or connection. So once a transaction is committed you should see al changes in any other Hibernate Session, JDBC connection or even your database UI manager tool.
You said that there was a primary key conflict. This can't happen if you use Hibernate identity or sequence generator. For the old hi-lo generator you can have problems if an external connection tries to insert records in the same table Hibernate uses an old hi/lo identifier generator.
This problem can also occur if there is a master/master replication anomaly. If you have multiple nodes and there is no strict consistency replication you can end up with primar key constraint violations.
Update
Solution 1:
When coordinating the new and the old code trying to insert the same entity, you could have a slect-than-insert logic running in a SERIALIZABLE transaction. The SERIALIZABLE transaction acquires the appropriate locks on tour behalf and so you can still have a default READ_COMMITTED isolation level, while only the problematic Service methods are marked as SERIALIZABLE.
So both the old code and the new code have this logic running a select for checking if there is already a row satisfying the select constraint, only to insert it if nothing is found. The SERIALIZABLE isolation level prevents phantom reads so I think it should prevent constraint violations.
Solution 2:
If you are open to delegate this task to JDBC, you might also investigate the MERGE SQL statement, if your current database supports it. Basically, this is an upsert operation issuing an update or an insert behind the scenes. This command is much more attractive since you can still run it with even on READ_COMMITTED. The only drawback is that you can't use Hibernate for it, and only some databases support it.
If you instanciate separately a SessionFactory for the old code and an EntityManagerFactory for new code, that can lead to different value in first level cache. If during a single Http request, you change a value in old code, but do not immediately commit, the value will be changed in session cache, but it will not be available for new code until it is commited. Independentely of any transaction or database locking that would protect persistent values, that mix of two different Hibernate session can give weird things for in memory values.
I admit that the injected EntityManager still uses Hibernate. IMHO the most robust solution is to get the EntityManagerFactory for the PersistenceUnit and cast it to an Hibernate EntityManagerFactoryImpl. Then you can directly access the the underlying SessionFactory :
SessionFactory sessionFactory = entityManagerFactory.getSessionFactory();
You can then safely use this SessionFactory in your old code, because now it is unique in your application and shared between old and new code.
You still have to deal with the problem of session creation-close and transaction management. I suppose it is allready implemented in old code. Without knowing more, I think that you should port it to JPA, because I am pretty sure that if an EntityManager exists, sessionFactory.getCurrentSession() will give its underlying Session but I cannot affirm anything for the opposite.
I've run into a similar problem when I had a list of enumerated lookup values, where two pieces of code would check for the existence of a given value in the list, and if it didn't exist the code would create a new entry in the database. When both of them came across the same non-existent value, they'd both try to create a new one and one would have its transaction rolled back (throwing away a bunch of other work we'd done in the transaction).
Our solution was to create those lookup values in a separate transaction that committed immediately; if that transaction succeeded, then we knew we could use that object, and if it failed, then we knew we simply needed to perform a get to retrieve the one saved by another process. Once we had a lookup object that we knew was safe to use in our session, we could happily do the rest of the DB modifications without risking the transaction being rolled back.
It's hard to know from your description whether your data model would lend itself to a similar approach, where you'd at least commit the initial version of the entity right away, and then once you're sure you're working with a persistent object you could do the rest of the DB modifications that you knew you needed to do. But if you can find a way to make that work, it would avoid the need to share the Session between the different pieces of code (and would work even if the old and new code were running in separate JVMs).
I have one MySql database instance with an Account table which maintains a Balance field. I have multiple Java applications each using a Jdbc to connect to the database that can potentially increase or decrease the value of the Balance field. How do I ensure that the Balance value is read, calculated and updated and that this process happens in isolation, and is 'aware' of any other Java processes that might be in the middle of doing the same thing?
The simple answer is to use transactions:
http://dev.mysql.com/doc/refman/5.0/en/commit.html
However, in the case you describe, I much prefer not to store the balance of an account as a column in a table, but to calculate it by summing the value of the transactions related to that account. It's far less sensitive to the integrity issues you raise, and you're less likely to run into obscure locking scenarios.
One simple approach is JDBCs transaction management. See java.sql.Connection.setAutoCommit() documentation. It enables you to explicitly disable automatic statement commits:
Connection c = /* retrieve connection */
c.setAutoCommit(false);
c.setTransactionIsolation(/* depends on your requirements */);
c.executeQuery(/* */);
c.executeUpdate(/* */);
c.commit(); /* or c.rollback() */
In a real world scenario you must introduce a finally block to commit or rolback the transaction, otherwise you may end up with deadlocks in your database.
Edit: If your Java applications are end user clients, you are always in risk that users directly connect to the database (e.g. using Access) bypassing your transaction management logic. That's one reason we began to place application servers in between. A solution might also be to implement a stored procedure, so that the clients do not interact with the tables at all.
If you are using InnoDB engine, then you can use MySQL record level locking to lock specific account record for updates from other clients.
UPDATE: Alternitively you can application-level locks described here.