Best method to archive data using Hibernate - java

I have a two tables chart and chartHistory which has similar table structure
chart_id NUMERIC(9,0)
chart_ref_id NUMERIC(9,0) NOT NULL
chart_property VARCHAR2(20) NOT NULL
chart_value VARCHAR2(100)
The entries in chart needs to be stored into the chartHistory table, when we get new property/value pairs for chart reference id.
I am planning to implement it using Hibernate in the following way
Get the list of values from CHART table using the chartReferenceId
List<Chart> chartList = chartDao.findChartByVisitRef(chartReferenceId);
( named query : findChartByRef = from Chart chart where chart.chartReferenceId=:chartReferenceId)
Use the retrieved list and build a chartHistoryList using the values from chartList and call the Hibernate method saveAll
chartHistoryDao.saveAll(chartHistoryList);
Once saved, remove the existing entries from the CHART table.
chartDao.deleteAll(chartList);
Build a newChartList for the new entried received, and do a hibernate saveAll
chartDao.saveAll(newChartList);
As you can see this executes four queries ie. for retrieving old records, saving them into the archive table, deleting the old entries and inserting the new values.
I would like to know whether there is a better way to implement this? Something of the sorts insert into .. (select from... ) would be more efficient I guess? Please advice.

Try the envers/audit module of Hibernate which handles all this for you automatically.
The main problem with envers/audit right now is to find the documentation. Envers (the original module) is supposed to be merged with Hibernate code since 3.5 but the core documentation doesn't mention anything about versioning or auditing even though InfoQ insists "Hibernate 4.1 Released With Improved Auditing Support"
So try the outdated documentation linked from the obsolete envers page and hope for the best.
Disclaimer: I haven't used Hibernate or envers for years.

Related

Retrieve table hierarchie from Hibernate

Now and then I come into the situation that I have to display the table hierarchie of a database for further operations, currently in a data migration project where I have to treat "leaf tables" (tables which are leafes in the table dependency tree) in a different way.
I've always wanted to use Hibernate's meta information to retrieve and display the table dependency tree, but never knew how to approach the problem.
So can anyone give me feedback on whether Hibernate provides an API to do this? I am not asking for a complete solution, the information if there is an API and what it is called is absolutely sufficient.
I want to solve the following questions:
Which tables are in the database?
Is a given table a root table (not dependant from other tables)?
Is a given table a leaf table (dependant from other tables but no table is dependant from the given table)?
Which tables are dependant from the given table?
On which tables does the given table depend?
I know how to retrieve the mapping between entities and tables:
How to discover fully qualified table column from Hibernate MetadataSources , but I want the relationship between the tables.
In a custom MetadataContributor you can access metadataCollector.getDatabase() which exposes the full relational model to you. You just have so save that into a static volatile variable and then access it later on in your app to do whatever you want to do with it.

Should I use mySQL Table Views or Spring Data JPA projections?

I have a mySQL relational database with football statistics that contains a table matches. I created a method in my Spring project to build a standings table. This method uses a projection because I need each match object to include the two team objects. This response (get all matches + get the two teams in each match) takes around 7 seconds.
The same information but within a View in my database takes 0.231 seconds.
I'm very new to Spring Data so my question is. Should I use table views when I need to join tables? Is there any advice against doing so?
I don't see any problem with using table views. You can map to them with JPA #Table annotation.
The only potential problem is when migrating databases (you will have to make sure Views are migrated correctly).
Hope this helps.

How to update Hibernate applications in production the right way?

I read the discussion about using hbm2ddl.auto=update in order to auto-update changes to the database schema.
The thread is from 2008 and I do not know how secure it is to use the auto-update mode today.
We are running a small JavaEE on a Glassfish with Hibernate 4.3.11 and PostgreSQL. We plan to use continious integration with Jenkins.
Is it useful to work with hbm2ddl.auto=update enabled? Or is it better to use an easy alternative to update/check the updates maybe manually?
I know it is hard to give a blanket statement.
You should not use hbm2ddl.auto=update to update production databases.
Few reasons:
Hibernate will only INSERT missing columns and not modify existing columns. Therefore, if you rename a property (Client to Customer), Hibernate will create a new column Customer, leaving the column Client untouched. You will need to manually "move" the data there and remove the orphan column.
Hibernate will not remove constraints on no longer mapped columns. Thus, if your Client column was NOT NULL, any insert query to that table will now fail in the first place, because Hibernate won't provide any data for the orphan column (Which still has it's NOT NULL constraint) anymore.
Hibernate will not touch data types of existing columns. So, if you change a property type from String to Date - Hibernate will leave the column definition as varchar.
Hibernate does not remove columns of which you deleted the property, leading to data-polution and worst-case (The constraints remain in place) to no longer working applications.
If you create additiional constriants on existing columns - hibernate will not create them, because the column already existed before. (You might miss important contraints on the production db you added on existing columns)
So, perform your updates on your own is safer. If you have to take into account what hibernate is doing and what not - you'd better do it on your own from the scratch.

Java Persist without Entity

I am working on an JavaEE application, and there are almost 1000+ tables in the database, now I have to query the records by the parametes from the client.
Generally I will create one Entity for each table, and create the Dao,Service to do the query.
However I meet two problems:
1 Number of the tables
As I said, 1000+ table with almost 40+ columns for each, it would a nightmare to create the entity one by one.
2 Scheme update
Even I can create the Entity by program, the schema of the data may change sometime which is out of my control.
And in my application, only read operations are related to these kinds of data,no update,delete,create required.
So I wonder if the following solution is possible:
1 Use Map instead of POJOs
Do not create POJOs at all, use the native Map to wrap the columns and values.
2 Row mapping
When querying using Hibernate or Spring JdbcTemplate or something else, use a mapper to map each row to an entry in the map.
If yes, I would use the ResultMetaData to detect the column name,type,value:
ResultMetaData rmd=rs.getMetaData();
for(int i=0;i<rmd.getColumnCount();i++){
Type t=rmd.getType(i)
if(t==....){
...
}else if(t=...){
...
}
}
Looks like part of JPA's job, any library can used here?
If not, any other alternatives?

Managing history records in a database

I have a web project that uses a database to store data that is used to generate tasks that would be processed for remote machines to alter that records and store new data. My problem here is that I have to store all that changes on each table but I don't need all these information. For example, a table A could have 5 fields but I only need 2 for historical purposes. Another table B could have 3 and I would have to add another one (date for example). Also, I don't need changes during daily task generation, only the most recent one.
Which is the best way to maintain a change history? Someone told me that a good idea is having two tables, the A (B) table and another one called A_history (B_history) with the needed fields. This is actually what I'm doing, using triggers to insert into history tables but I don't feel comfortable with this approach. My project uses Spring (Spring-data, Hibernate and JPA) and if I change the DB (currently MySQL) I'd have to migrate triggers. Is there a good way to manage history records? Tables could be generated with Hibernate/JPA annotations.
If I maintain the two tables approach, can I add a method to the repository to fetch rows from current table and history table at once?
For this pourpose there is a special Hibernate Envers project. See official documentation here. Just configure it, annotate necessary properties with #Audited annotation and that's all. No need for DB triggers.
One pitfall: if you want to have a record for each delete operation then you need to use Session.delete(entity) way instead of HQL "delete ...".
EDIT. Also take a look into native auditing support of spring data jpa.
I am not a database expert. What I have seen them do boils down to a few ways of approach.
1) They add a trigger to the transactional table that copies inserts and updates to a history table but not deletes. This means any queries that need to include history can be done from the history table since all the current info is there too.
a) They can tag each entry in the history table with time and date and
keep track of all the states of the original records.
b) They can only
keep track of the current state of the original record and then it
settles when the original is deleted.
2) They have a periodic task that goes around and copies data marked as deletable into the history table. It then deletes the data from the transactional table. Any queries in the transactional table have to make sure to ignore the deletable rows. Any queries that need history have to search both tables and merge the results.
3) If the volume of data isn't too large, they just leave everything in one table and mark some entries as historical. Queries have to ignore historical rows. Queries that include history are easy. This may slow down database access as the table grows to include many unused rows but that can sometimes be ameliorated by clever use of indexes.

Categories

Resources