Force Hibernate To Create Tables After Dropping and Recreating database - java

I am developing a web application with java 2 ee. I also use hibernate and mysql.
in order to restore the backup file, in some point in my application i need to drop the current database and recreate it, i do it as follow :
Connection conn = (Connection) DriverManager.getConnection("jdbc:mysql://localhost/?user=user&password=pass");
Statement statement = (Statement) conn.createStatement();
statement.executeUpdate("DROP DATABASE tcs;");
statement.executeUpdate("CREATE DATABASE tcs charset=utf8 collate=utf8_persian_ci;");
after dropping and recreating i need to initialize database with default user (spring security user)
User admin = new User();
UserAuthority ROLE_USER = new UserAuthority("ROLE_USER");
ROLE_USER.save();
admin.addUserAuthority(ROLE_USER);
admin.setEnabled(true);
admin.save();
but at the last line application throws this exception
Hibernate: insert into roles (authority) values (?)
[DEBUG][16:19:17,734] [http-bio-8080-exec-10] NewPooledConnection:367 com.mchange.v2.c3p0.impl.NewPooledConnection#bcbe33a handling a throwable.
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'tcs.roles' doesn't exist
i know hibernate creates tables at startup but in this case it fails to recreate the tables after a drop/recreate , so how can i force hibernate to create tables again?
or hypothetically is there something like Hibernate.createTable(Class) ?

You need to add the following property to your configuration:
Drop and Recreate everytime SessionFactory is created and destroyed:
<property name="hbm2ddl.auto">create-drop</property>
Other possible options:
validate: validate the schema, makes no changes to the database.
update: update the schema.
create: creates the schema, destroying previous data.

for future googlers :
it was so simple after all , i just needed to build session factory so i added this line and it worked like charm :
new Configuration().configure().buildSessionFactory();
note that buildSessionFactory() is deprecated in hibernate 4 but i guess you can use the code here to do the same.

Related

Spring Transaction handling with EclipseLink

I am new to databases and transactions. I find a lot of different information up-to-date and am currently trying to organize my thoughts.
Regarding the context, I'm trying to test the current isolation level with the SQL Server, but I don't succeed.
For this I use Spring Transaction together with Eclipse Link. I found some information about Spring transactions (https://www.marcobehler.com/guides/spring-transaction-management-transactional-in-depth). However, there is still a concept of the works unit and now I don't know what is currently being used (https://wiki.eclipse.org/Introduction_to_EclipseLink_Transactions_(ELUG)#Unit_of_Work_Architecture)
What I am trying to test:
I have an Entity User (id, firstname, lastname). I have an entry in table id = 1, firstname = foo lastname = bar
I have a service and transaction. IMHO default is isolation READ_COMMIT for SQL Server
#Transactional
public User updateUser(){
User updateUser = new User(1, "new firstname", "new lastname");
User updatedUser = userRepository.save(updateUser); --> em.merge
return updatedUser;
}
So far so good. What I do not understand now. I set a breakpoint in the return.
At the same time I opened a second SQL client and executed the following SQL.
SET IMPLICIT_TRANSACTIONS ON
UPDATE
User
SET
lastname = 'complete new',
WHERE
id = 1
COMMIT TRAN
What I would expect is that the SQL statement will wait for the Spring transaction to complete. BUT this is currently not the case, the SQL statement is simply carried out.
Then lastname is in the table lastname "complete new" then I resume the breakpoint and then the lastname is "new lastname". This behavior I cannot understand. Is this normal or is this because of the unit work of eclipse link?
EclipseLink buffers SQL statements that need to be executed for as long as possible in order to reduce the lock time in the RDBMS. In your particular case the JDBC driver will receive the UPDATE statement when Spring Data JPA commits the transaction. You can verify it by enabling SQL logging in EclispeLink: stackoverflow.com/q/2374395/17695211
After enabling SQL logging you'll see that there won't be any SQL debug output in the console at your breakpoint. It will appear after the return. If you really want to see the locking effect, you need to write the repository without Spring Data JPA with a #PersistenceContext-injected EntityManager and call EntityManager.flush which will flush SQL statement buffer of EclipseLink to the JDBC driver before the breakpoint.
Alternatively (and if you feel adventurous), you may try looking for a place in the EclipseLink source code where it executes the corresponding PreparedStatement, and set the breakpoint right after it.

Oracle: Read-only access to the schema for another user?

I have a schema and a user with the same name: products. For development I would like to use it in a read-only mode from a java application. Therefore, I created a new user for the read-only application.
CREATE USER PRODUCTS_READONLY IDENTIFIED BY PRODUCTS_READONLY;
GRANT CREATE SESSION to PRODUCTS_READONLY;
BEGIN
FOR tab IN (SELECT table_name FROM all_tables WHERE owner = 'PRODUCTS') LOOP
EXECUTE IMMEDIATE 'GRANT SELECT ON PRODUCTS.'||tab.table_name||' TO PRODUCTS_READONLY';
END LOOP;
END;
Running the application I got the error that the table did not exist. Searching on the internet for solution, I came across SYNONYM. So I added synonym to the schema:
CREATE SYNONYM PRODUCTS_READONLY FOR PRODUCTS;
Now, I am getting this error in my java application:
ERROR org.hibernate.util.JDBCExceptionReporter - ORA-17074 invalid name pattern.: PRODUCTS_READONLY.PRODUCT_TYPE
What is wrong with my approach?
--UPDATE--
Seems like creating synonyms for schema was removed in 10g (Oracle: is it possible to create a synonym for a schema?). If I create schema for each object in the target schema, I would have to do the same every time a table is added to the target schema or any other changes to the any other objects in the target schema? That sounds cumbersome...
--UPDATE 2--
Seems like a trigger with alter session is a possible solution, but will it make the tables read-only so long the user has only SELECT privilege?
If you have control over the way your application connects (e.g. an initialization statement for your connection pool), all you need to do is run:
ALTER SESSION SET CURRENT_SCHEMA = PRODUCTS;
From that point onward (during the lifetime of the session) any unqualified object name will be searched for in the PRODUCTS schema.
All grants given to PRODUCTS_READONLY will be in effect. The session will run under the credentials (and security restrictions) of the original user used to log in.
If you can not change the way the connection is established or initialized a logon trigger should also accomplish this:
create or replace trigger logon_trg
after logon on database
begin
if (user = 'PRODUCTS_READONLY') then
execute immediate 'alter session set current_schema = products';
end if;
exception
when others then null; -- prevent a login failure due to an exception
end logon_trg;
/
Note that it's crucial to trap any exception, because otherwise a potential error in the executed SQL will effectively log everyone out off the database. So use with care and test it well before putting that into production.
I am not sure you can create a synonym for schema.
But you can create a synonym for every object in the remote schema, e.g.
begin
for c in (select t.table_name from table_privileges t where grantee = 'PRODUCTS_READONLY') loop
execute immediate 'create synonym '||c.table_name||' for PRODUCTS.'||c.table_name;
end loop;
end;
Don't be confused with table_name, it handles all types of objects there.

JDBC Change Default Schema

I'm trying to connect to a sql server 2005 database via JDBC.
I get the error:
com.microsoft.sqlserver.jdbc.SQLServerException: The SELECT permission
was denied on the object 'MyTable', database 'MyDatabase', schema
'dbo'.
The schema I use to connect is "MyUser". How do I connect using MyUser as opposed to dbo?
Thanks!
To clear things up: You connect to SQL Server using a user, not a schema. You don't say what version of SQL Server you're connecting to, but it used to be the case that the two were equivalent. As of 2005+, that is no longer true.
dbo is the default schema (think of it as a namespace); what the error message is telling you is the user you are connecting with (If I understand correctly, that's MyUser) does not have permission to SELECT from the MyTable table, which is part of the dbo schema in the MyDatabase database.
The first thing to do is confirm whether or not the user you're connecting with does or does not have SELECT permissions on that table. The second thing to do is, if it doesn't, either give MyUser that permission or use a different user to perform the SELECT statement.
i found that you have to specify your schema in your POJOS definitions.
In my case I got the same trouble using JPA (Entities / Annotations) and I realized that specifing the schema property in the #Table annotation works.
for example:
#Table(name = "address", **schema="*dbo*"**, catalog = "petcatalog")
I hope this helps you.

HSQLDB and Hibernate/JPA - not persisting to disk?

Something of an novice with HSQL and Hibernate...
em.getTransaction().begin();
for (Activity theActivity : activities) {
em.persist(theActivity);
}
em.getTransaction().commit();
em.close();
followed by...
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
System.out.println("QUERY:: "
+ em.createQuery("SELECT COUNT(*) FROM " + Activity.class.getName()).getSingleResult()
.toString());
em.getTransaction().commit();
Prints 25000 (the number of Activity objects in activities). But when I run this test again, the number of objects in the count(*) doesn't increase (and is 0 at the beginning of the program). So the objects aren't getting durably written.
This is my hsqldb connection string:
name="hibernate.connection.url" value="jdbc:hsqldb:file:data/cmon"
so it's not an in-memory database as far as I know...
Does anyone have any ideas why the objects aren't getting persisted beyond a single JVM session? Happy to supply more information but there's so much state associated with Hibernate / JPA / HSQL that it's not clear exactly what is pertinent.
Does anyone have any ideas why the objects aren't getting persisted beyond a single JVM session?
HSQLDB doesn't write changes immediately to disk after a commit (see "WRITE DELAY"), HSQLDB is not Durable by default (that's from where "performances" are coming from).
Either try to set the connection property shutdown=true in the connection string to get the changes written when the last connection will end.
jdbc:hsqldb:file:data/cmon;shutdown=true
If it doesn't help, try to set the WRITE DELAY to 0 (or false). If you're using HSQLDB 1.8.x, use the SQL command:
SET WRITE_DELAY 0
If you're using HSQLDB 2.0.x, you can now also use a connection property hsqldb.write_delay:
jdbc:hsqldb:file:data/cmon;hsqldb.write_delay=false
The solution is :
<property name="dialect">org.hibernate.dialect.HSQLDialect</property>
in hibernate.cfg.xml
This is rest of my configuration:
Libs:
HsqlDb 2.0.0
Hibernate 3.5.6
Url:
<property name="connection.url">jdbc:hsqldb:file:data/mydb;shutdown=true;hsqldb.write_delay=false;</property>
Did you set hibernate.hbm2ddl.auto to create-drop in your persistence.xml? This drops your tables and re-creates them on every startup.
You can set it to update instead, or if you want to manage the schema yourself, then set it to validate.
I was using HSQL DB version 2.2.5.
I tried above approaches i.e. setting shutdown=true and hsqldb.write_delay=false
It did not work. As suggested in some blog, I added statement
org.hsqldb.DatabaseManager.closeDatabases(0);
after transaction commit. But it did not work.
HSQL DB version 2.2.9 seems better than this. With one workaround it solves this problem. To handle above problem take following steps :-
1) hsqldb.jar from lib of HSQL DB version 2.2.9
2) In hibernate config xml just specify URL
I am using HSQL file-based database.
<property name="hibernate.connection.url">jdbc:hsqldb:file:D:\JavaProj\TmpDBLocation\myKauDB</property>
3) In your program at the end write statement
org.hsqldb.DatabaseManager.closeDatabases(0);
Now run the hibernate program that commits the data to DB.
Check HSQL DB by opening it in standalone mode and with URL
jdbc:hsqldb:file:D:\JavaProj\TmpDBLocation\myKauDB
You should see your changes persisted in DB.
Simply close your EntityManagerFactory with HSQL in filemode, after the commit to really persist datas...
Closing sessionfactory worked for me.

Spring Jdbc atomicity with alter table

I'm trying to write an equivalent of Rails data model evolution/rollback mechanism using Spring Jdbc.
Spring Jdbc transactionnal insert/replace works very well (DataSourceTransactionManager with PROPAGATION_REQUIRED under InnoDB mysql 5) :
// Transaction begins
getJdbcTemplate().execute("replace into aTable ...");
getJdbcTemplate().execute("wrong request");
getJdbcTemplate().execute("replace into aTable ...");
// none are commited
but alter doesn't :
// Transaction begins
getJdbcTemplate().execute("alter table aTable add column `columnForTest` ...");
getJdbcTemplate().execute("wrong request");
getJdbcTemplate().execute("alter table aTable add column `columnForTest` ...");
// the first alter is commited
Is there a way to achieve atomicity (all-or-none behavior) with alter ?
Thanks in advance
ALTER TABLE (and other DDL operations) are usually non-transactional, depending on the database. Spring and JDBC have no control over this. If a non-transactional operation is performed inside a transaction, it will be performed non-transactionally.
So it comes down to the database, and how it is configured, rather than being an issue with the client.

Categories

Resources