Create database script mySQL - java

I have dynamic web java project where I am using spring-MVC/hibernate. In my xml config file I have a bean for setting up my sessionFactory (all dependencies - jdbc url etc. for my local database). Is there a way I can send this project + database to my friend and it will work ? I am wondering because in xml config file I have the exact jdbc url, hostname, port etc. which doesnt have to be the same on my friend's laptop but is there a way to create some script that will create database with the exactly same properties as my local database ?
EDIT - here is config file
<!-- Define Database DataSource / connection pool -->
<bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/java_task?useSSL=false" />
<property name="user" value="me" />
<property name="password" value="me" />
<!-- these are connection pool properties for C3P0 -->
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="20" />
<property name="maxIdleTime" value="30000" />
</bean>
<!-- Define Hibernate session factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="packagesToScan" value="com.javatask.entity" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>

[...] is there a way to create some script that will create database
with the exactly same properties as my local database?
In the hibernate-tools jar, Hibernate provides a SchemaExport tool that supports what you want to do.
You can write a little program yourself to use it, but I think most folks don't "roll their own." I think it's common to use a plugin for your build system.
Are you using Maven? You could use something like this: https://github.com/Devskiller/jpa2ddl

Is there a way I can send this project + database to my friend and it
will work ?
Yes, u can put your code in a public repository like Github, and ur friend can clone it from there
I am wondering because in xml config file I have the exact jdbc url,
hostname, port etc. which doesnt have to be the same on my friend's
laptop but is there a way to create some script that will create
database with the exactly same properties as my local database ?
We don't know ur code, but if u have provided absolute path in ur configuration then it will fail in ur friend's laptop. For a better answer, please provide ur configuration code
You can read about absolute path here
Update
I don't see any problem in your config code. it should work well in another system. About uploading the database, u can simply export it from ur database, and put the deattached file into the folder of ur current project. Once u push ur code to the repo the database would be there too. Then the other person, will get it again by the other codes. Again there is no problem.
Your firend must get sure that he has Mysql, and it is working on port 3306. But, there shouldn't be any problem. why do u think, it would fail?

Related

Hibernate JTA : Read DB connection parameters per environment

I am writing a javaEE application, using hibernate. The application will be running on multiple environments (dev, qa, prod etc.) & will have separate dbs's associated with each of them. I would like to set the hibernate properties like jdbc-url, username , password etc. separately for each of these environments.
My current persistence.xml looks like :
<persistence-unit name="PU" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<validation-mode>CALLBACK</validation-mode>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.OracleDialect" />
<property name="hibernate.hbm2ddl.auto" value="validate" />
<property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
<property name="hibernate.event.merge.entity_copy_observer" value="allow"/>
<property name="hibernate.connection.driver_class" value="oracle.jdbc.OracleDriver"/>
<property name="hibernate.connection.url" value="jdbc:oracle:thin:#host/schema"/>
<property name="hibernate.connection.username" value="abc"/>
<property name="hibernate.connection.password" value="***"/>
</properties>
</persistence-unit>
I am using the persistence unit as follows in my java code:
#PersistenceContext(unitName = "PU")
private EntityManager em;
Is there a way that I can inject the hibernate properties, which are stored in separate properties files, into EntityManager for different environments ?
Please note that I am using JTA and hence cannot use EntityManagerFactory. Also I am not & do not want to use spring.
It is really a BAAAAAAD idea to include environment-specific information in your application WAR/EAR bundle (either by including multiple configs, or by creating different bundles for different environment). Different database, for example, should be maintained in the container.
In your case, your persistence.xml should look like:
<persistence>
<persistence-unit name="PU">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/fooAppDs</jta-data-source>
<properties>
... ...
</properties>
</persistence-unit>
</persistence>
and of course you should have corresponding resource-ref for jdbc/fooAppDs.
By doing so, you can deploy your application in any environment. You just need to create correct datasource in your container and assign it to jdbc/fooAppDs.
Another approach I believe will work, though I will not recommend, is by creating hibernate.cfg.xml in classpath. You may want to have a local file system location and add that in classpath, instead of putting the file in your JAR/WAR/EAR.
Since you do not want to use external library such as Spring to bootstrap your persistence units, why not use your build system to do this. If you are using maven, you can use mix of maven filtering and profiles to filter based on properties file or if you are using any other build tool, you can add a task (or equivalent) to copy file contents from different files to actual file depending upon some external system/environmental variable.
We used maintain property files for each environment such as DEV,QA,PROD,UAT etc in different files and copy one of them during build.
Ant build
<property environment="env" />
<!-- ***** COMMAND LINE ARGUMENTS DEMOED HERE -->
<property name="build_type" value= "${env.build_type}"/>
<copy todir="deploy">
<fileset dir="src_dir"/>
<globmapper from=${env.build_type}".persistence.xml" to="persistence.xml"/>
</copy>
Run build like this
ant -Denv.build_type=PROD
This will copy PROD.persistence.xml to persistence.xml
ant -Denv.build_type=DEV
This will copy DEV.persistence.xml to persistence.xml
With Spring Profile you could initiate entity manager beans depending upon the active profile that will refer to the persistence.xml like dev-persistence.xml, test-persisitence.xml, prod-persistence.xml of your environment. And you can set Active profile using web.xml. Mostly the web.xml won't change that much so you can keep the web.xml in your repository with the spring profile active property set for that enviornment.
you can configure your spring-config.xml file as following
MYSQL
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/kaya_db" />
<property name="username" value="root" />
<property name="password" value="nxtlife" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="packagesToScan" value="com.nxtlife.model" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory">
</bean>
2.Similar for other database like oracle,postgre with different name of datasource,sessionfactory and transactionmanager.
3. Finally you can get object of session factory using following sessionfactory name
#Modifier("sessionfactoryname")
#Autowired
private SessionFactory obj;
similar for different database

Seam/Hibernate: liquibase before JPA startup

I have a Java EE web application (hibernate3, seam) that I'm using in Weblogic container.
I want to introduce Liquibase for schema migrations.
Currently we use
<property name="hibernate.hbm2ddl.auto" value="update"/>
which we want to drop because it can be dangerous.
I want the migration to automatically happen at deployments, so I'm using the servlet listener integration.
In web.xml, the first listener is:
<listener>
<listener-class>liquibase.integration.servlet.LiquibaseServletListener</listener-class>
</listener>
Sadly, this listener comes into play after the Hibernate initialization and it throws missing table errors (because the schema is empty).
I'm google-ing like a boss for hours and I'm a bit confused now.
Thanks in advance
UPDATE
If I set <property name="hibernate.hbm2ddl.auto" value="none" />, liquibase finishes it's job successfully and the app starts up as expected. If I set validate, it seems like hibernate schema validation takes place before liquibase and it cries because of missing tables.
UPDATE
It seems like Seam initializes Hibernate, but Liquibase listener is listed before SeamListener, so I have no clue on how to enable schema validation and liquibase at the same time...
My understanding is that the LiquibaseServletListener requires the path to change log file which is passed using liquibase.changelog context param. So you already have a change log generated or am I missing something here ?
You can take a look at the liquibase hibernate integration library provided by Liquibase.
This library works with both the classic hibernate configuration (via .cfg and .xml files) as well as JPA configuration via persistence.xml.
AFAIK, generating the changelog and running the change log are two seperate process. Liquibase hibernate integration library helps in generating the change log from the diff of current state of entities in persistence unit and the current database state.
How to determine the order of listeners in web.xml
You should place:
<listener>
<listener-class>liquibase.integration.servlet.LiquibaseServletListener</listener-class>
</listener>
before ORM or framework other related listeners.
I use Spring beans LiquiBase activation to reduce DB authentication data duplication by using already provided datasource bean:
<bean id="liquibase" class="liquibase.integration.spring.SpringLiquibase">
<property name="dataSource" ref="dataSource" />
<property name="changeLog" value="classpath:sql/master.sql" />
<property name="defaultSchema" value="PRODUCT" />
</bean>
To restrict order use depends-on attribute:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
depends-on="liquibase">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="packagesToScan" value="product.domain" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
</props>
</property>
</bean>

Oracle + dbunit gets AmbiguousTableNameException

I am using dbunit to create database backups, which can be imported and exported. My application can use several database engines: MySQL, PostgreSQL, SQLServer, H2 and Oracle.
All of the above work fine with the following code:
// Connect to the database
conn =BackupManager.getInstance().getConnection();
IDatabaseConnection connection = new DatabaseConnection(conn);
InputSource xmlSource = new InputSource(new FileInputStream(new File(nameXML)));
FlatXmlProducer flatXmlProducer = new FlatXmlProducer(xmlSource);
flatXmlProducer.setColumnSensing(true);
DatabaseOperation.CLEAN_INSERT.execute(connection,new FlatXmlDataSet(flatXmlProducer));
But on Oracle I get this exception:
!ENTRY es.giro.girlabel.backup 1 0 2012-04-11 11:51:40.542
!MESSAGE Start import backup
org.dbunit.database.AmbiguousTableNameException: AQ$_SCHEDULES
at org.dbunit.dataset.OrderedTableNameMap.add(OrderedTableNameMap.java:198)
at org.dbunit.database.DatabaseDataSet.initialize(DatabaseDataSet.java:231)
at org.dbunit.database.DatabaseDataSet.getTableMetaData(DatabaseDataSet.java:281)
at org.dbunit.operation.DeleteAllOperation.execute(DeleteAllOperation.java:109)
at org.dbunit.operation.CompositeOperation.execute(CompositeOperation.java:79)
at es.giro.girlabel.backup.ImportBackup.createData(ImportBackup.java:39)
at es.giro.girlabel.backup.handlers.Import.execute(Import.java:45)
From the docs:
public class AmbiguousTableNameException extends DataSetException
This exception is thrown by IDataSet when multiple tables having the
same name are accessible. This usually occurs when the database
connection have access to multiple schemas containing identical table
names.
Possible solutions:
1) Use a database connection credential that has
access to only one database schema.
2) Specify a schema name to the
DatabaseConnection or DatabaseDataSourceConnection constructor.
3) Enable the qualified table name support (see How-to documentation).
For whom uses SpringDBUnit. I had struggled with this very annoying issue. I had ended up solving the issue by adding the configuration for com.github.springtestdbunit.bean.DatabaseConfigBean and com.github.springtestdbunit.bean.DatabaseDataSourceConnectionFactoryBean.
This is my full spring context for SpringDBUnit
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#localhost:1521/XE" />
<property name="username" value="xxxx" />
<property name="password" value="xxxx" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>xxx.example.domain.Person</value>
</list>
</property>
</bean>
<bean id="dbUnitDatabaseConfig" class="com.github.springtestdbunit.bean.DatabaseConfigBean">
<property name="skipOracleRecyclebinTables" value="true" />
<property name="qualifiedTableNames" value="true" />
<!-- <property name="caseSensitiveTableNames" value="true"/> -->
</bean>
<bean id="dbUnitDatabaseConnection"
class="com.github.springtestdbunit.bean.DatabaseDataSourceConnectionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="databaseConfig" ref="dbUnitDatabaseConfig" />
<property name="schema" value="<your_schema_name>"/>
</bean>
Setting the database schema fixed it for me:
#Bean
public DatabaseDataSourceConnectionFactoryBean dbUnitDatabaseConnection(final DataSource dataSource){
final DatabaseDataSourceConnectionFactoryBean connectionFactory = new DatabaseDataSourceConnectionFactoryBean();
connectionFactory.setDataSource(dataSource);
connectionFactory.setSchema(DB_SCHEMA);
return connectionFactory;
}
I had the same AmbiguousTableNameException while executing Dbunits aginst Oracle DB. It was working fine and started throwing error one day.
Rootcause: while calling a stored procedure, it got modified by mistake to lower case. When changed to upper case it stared working.
I could solve this also by setting the shema name to IDatabaseTester like iDatabaseTester.setSchema("SCHEMANAMEINCAPS")
Also please make sure your connection doesn't access only to many schemas having same table name.
You might encounter issues when importing data from Hibernate before DBUnit runs. According to the database you are using, the casing of table and column names could be important.
For example, in HSQL, database names must be declared in uppercase.
In case you import data via Hibernate's import.sql, make sure the table names are also in uppercase there, otherwise you'll end up with the following problem:
Hibernate creates the tables in lower case
DBUnit reads the table names from the DB in lower case
DBUnit tries to import its datasets using upper case table names
You end up in a mess, with the ambiguous name exception.
Remember to also check whether multiple tables were created during a previous run (both upper and lower case), in which case you need to clean it up too.

application connect to database

I am working on an application that will be used by schools. Each school will set up their on database. And each school will provide their own "settings" file to the application. The settings file will contain the database url for the specific school who made the settings file. This is so that a student using the application can just load a different settings file if they want to connect to a different database.
My question is, how do i protect the username and password used to connect to the database? So, that ONLY the application has read and write access to the database. And the application has read and write access to only that specific school?
If you need more information, please let me know.
Thanks
Take a look at Jasypt, it is a java library which allows the developer to add basic encryption capabilities to his/her projects with minimum effort, and without the need of having deep knowledge on how cryptography works.
In case you use Spring, you can define your db.properties as:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/yourdb
jdbc.username=userName
jdbc.password=ENC(A6L729KukPEx7Ps8didIUWb01fdBRh7d)
and configure it with Jasypt and Spring as:
<bean class="org.jasypt.spring.properties.EncryptablePropertyPlaceholderConfigurer">
<constructor-arg>
<bean class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
<property name="config">
<bean class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
<property name="algorithm" value="PBEWithMD5AndDES" />
<property name="passwordEnvName" value="APP_ENCRYPTION_PASSWORD" />
</bean>
</property>
</bean>
</constructor-arg>
<property name="locations">
<list>
<value>classpath:/META-INF/props/db/db.properties</value>
</list>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
This would hide the actual password (you can do the same for the username) from students, so they would not be able to derive the connection string from looking at the properties file.
In case you are not using Spring, here is a Jasypt guide to achive the same "manually"

How can I configure Hibernate to use SSL to talk to the DB server?

I have an existing java webapp that uses Hibernate for it's persistence. I've been told that I have to have to talk to the DB encrypted - so my first thought is to set it up to do the communication via SSL - and went through figured out how to set up Oracle to listen for JDBC over SSL -
http://www.oracle.com/technology/tech/java/sqlj_jdbc/pdf/wp-oracle-jdbc_thin_ssl_2007.pdf
And wrote a quick test class to verify that it was setup and working (connecting via standard JDBC). That left me with the issue of configuring Hibernate - unfortunately I don't see how hibernate supports it?
Hibernate works with standard JDBC data sources, so there is no need for Hibernate-specific configuration.
Here's an quick example that should work when configuring Hibernate with Spring:
<bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource">
<property name="URL"><value><!-- JDBC URL that specifies SSL connection --></value></property>
<!-- other relevant properties, like user and password -->
<property name="connectionProperties>
<value>
oracle.net.ssl_cipher_suites: (ssl_rsa_export_with_rc4_40_md5, ssl_rsa_export_with_des40_cbc_sha)
oracle.net.ssl_client_authentication: false
oracle.net.ssl_version: 3.0
oracle.net.encryption_client: REJECTED
oracle.net.crypto_checksum_client: REJECTED
</value>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- classes etc -->
</bean>
Try this:
<property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://blablaba:8443/dbname?useSSL=true</property>
<property name="hibernate.connection.verifyServerCertificate">false</property>
<property name="hibernate.connection.requireSSL">true</property>
<property name="hibernate.connection.autoReconnect">true</property>
<property name="hibernate.connection.username">bablablab</property>
<property name="hibernate.connection.password">clclclclc</property>
related links
http://www.razorsql.com/articles/mysql_ssl_jdbc.html
http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-using-ssl.html
http://www.javabeat.net/qna/164-hibernate-jdbc-and-connection-properties/
Please add following property in Hibernate configuration file to enable SSL :
<property name="hibernate.connection.verifyServerCertificate">false</property>
<property name="hibernate.connection.useSSL">true</property>
Should be handled by the driver but you may have to do some configuration. Oracle Docs
I had the jdbcURL
jdbc:postgresql://jdbcurl?sslmode=require&sslrootcert=location_to_cert1&sslcert=location_to_cert2&sslkey=location_to_cert3.
All I had to do was to replace all the & with &.
My new jdbcURL looks like
jdbc:postgresql://jdbcurl?sslmode=require&sslrootcert=location_to_cert1&sslcert=location_to_cert2&sslkey=location_to_cert3

Categories