Статьи

Liquibase и Hibernate


Я изучал проект liquibase и анализировал его преимущества как инструмента управления базами данных.

Мы создаем приложение под названием LiquibaseTryOuts. Структура проектов следующая:

Зависимости перечислены ниже

Я заметил, что документации по настройке liquibase с помощью ant-скриптов не так много. Поэтому я создал ant-скрипт для нашего приложения. Вот сценарий муравья:

<?xml version="1.0" encoding="UTF-8"?>

<project name="liquibase-sample">

<property file="liquibase.properties"/>

<path id="lib.path" >
<fileset dir="lib1" />
</path>

<target name="update-database">
<taskdef name="updateDatabase" classname="liquibase.ant.DatabaseUpdateTask"
classpathref="lib.path" />
<updateDatabase
changeLogFile="${changeLogFile}"
driver="${driver}"
url="${url}"
username="${username}"
password="${password}"
dropFirst="${dropfirst}"
classpathref="lib.path"/>
</target>

<target name="rollback-database">
<taskdef name="rollbackDatabase" classname="liquibase.ant.DatabaseRollbackTask"
classpathref="lib.path" />
<rollbackDatabase
changeLogFile="${changeLogFile}"
driver="${driver}"
url="${url}"
username="${username}"
password="${password}"
classpathref="lib.path"
rollbackTag="${tag}"
>
</rollbackDatabase>
</target>

<target name="tag">
<taskdef name="tagDatabase" classname="liquibase.ant.TagDatabaseTask"
classpathref="lib.path" />
<tagDatabase
changeLogFile="${changeLogFile}"
driver="${driver}"
url="${url}"
username="${username}"
password="${password}"
classpathref="lib.path"
tag="${tag}"
>
</tagDatabase>
</target>

<target name="generateChangeLog">
<taskdef name="generateChangeLogDatabase" classname="liquibase.ant.GenerateChangeLogTask"
classpathref="lib.path" />
<tagDatabase
outputFile="${outputFile}"
driver="${driver}"
url="${url}"
username="${username}"
password="${password}"
classpathref="lib.path"
>
</tagDatabase>
</target>

<target name="diff-database">
<taskdef name="diffDatabase" classname="liquibase.ant.DiffDatabaseTask"
classpathref="lib.path" />
<tagDatabase
driver="${driver}"
url="${url}"
username="${username}"
password="${password}"

baseUrl="${url}"
baseUsername="${username}"
baseUassword="${password}"

outputDiffFile="${outputDiffFile}"
classpathref="lib.path"
>
</tagDatabase>
</target>


</project>

Затем мы используем hibernate теперь, как и мой блог 30 мая мы используем hibernate с аннотациями JPA. Вот файл конфигурации:

<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>

<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/liquibasetestdb</property>
<property name="connection.username">monty</property>
<property name="connection.password">some_pass</property>

<!– JDBC connection pool (use the built-in) –>
<property name="connection.pool_size">1</property>

<!– SQL dialect –>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>


<!–<mapping package="liquibase.database.pojo"/>–>
<mapping class="liquibase.database.pojo.Users"/>


<!– <mapping resource="test/animals/orm.xml"/>–>
</session-factory>
</hibernate-configuration>

Теперь файлы классов для этого проекта совпадают с файлами, которые использовались для блога 30 мая с одним или двумя дополнительными файлами. Вот диаграмма UML:

Теперь нам нужны некоторые журналы изменений, которые соответствуют спецификациям ликвазы, они будут следующими

included.changelog.xml

<?xml version="1.0" encoding="UTF-8"?>

<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.7"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.7 http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.7.xsd">
<preConditions>
<dbms type="mysql"/>
</preConditions>

<changeSet id="1" author="gabriel">
<createTable tableName="news">
<column name="id" type="int" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="title" type="varchar(50)"/>
</createTable>
</changeSet>

<changeSet id="2" author="gabriel" context="test">
<insert tableName="news">
<column name="title" value="Liquibase 0.8 Released"/>
</insert>
<insert tableName="news">
<column name="title" value="Liquibase 0.9 Released"/>
</insert>
</changeSet>

<changeSet id="3" author="gabriel" context="demo">
<insert tableName="news">
<column name="title" value="Liquibase 1.0 Released"/>
</insert>
</changeSet>
</databaseChangeLog>

Далее включено2.changelog.xml

<?xml version="1.0" encoding="UTF-8"?>

<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.7"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.7 http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.7.xsd">
<preConditions>
<dbms type="mysql"/>
</preConditions>

<changeSet id="1" author="gabriel">
<createTable tableName="records">
<column name="id" type="int" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="title" type="varchar(50)"/>
</createTable>
</changeSet>

<changeSet id="2" author="gabriel" context="test">
<insert tableName="records">
<column name="title" value="Liquibase 0.8 Released"/>
</insert>
<insert tableName="records">
<column name="title" value="Liquibase 0.9 Released"/>
</insert>
</changeSet>

<changeSet id="3" author="gabriel" context="demo">
<insert tableName="records">
<column name="title" value="Liquibase 1.0 Released"/>
</insert>
</changeSet>
</databaseChangeLog>

included3.changelog.xml

<?xml version="1.0" encoding="UTF-8"?>

<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.7"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.7 http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.7.xsd">
<preConditions>
<dbms type="mysql"/>
</preConditions>

<changeSet id="1" author="gabriel">
<createTable tableName="register">
<column name="id" type="int" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="title" type="varchar(50)"/>
<column name="name" type="varchar(100)"/>
</createTable>
</changeSet>

<changeSet id="2" author="gabriel">
<dropTable tableName="register"/>
<rollback changeSetId="1" changeSetAuthor="gabriel"/>
</changeSet>

</databaseChangeLog>

И включенный4.changelog.xml

И нам нужен файл liquibase.properties:

changeLogFile=included4.changelog.xml
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/liquibasetestdb
username=monty
password=some_pass

#for diff between two databases
baseUrl=jdbc:mysql://localhost:3306/liquibasetestdb
baseUsername=monty
basePassword=some_pass

dropFirst=false
tag=version 1.4
outputFile=outputFile.xml
outputDiffFile=outputFile.txt

Когда мы добавим файл в наш редактор мувиков затмения, это будет вид:

Теперь, запустив откат-базу данных, в качестве примера получаем:

Buildfile: /home/gabriel/eclipse/eclipse/opensource-workspace/LiquibaseTryOuts/build.xml
rollback-database:
[rollbackDatabase] Lock Database
[rollbackDatabase] Successfully acquired change log lock
[rollbackDatabase] included4.changelog.xml is using schema version 1.7 rather than version 1.9
[rollbackDatabase] Reading from `DATABASECHANGELOG`
[rollbackDatabase] Release Database Lock
[rollbackDatabase] Successfully released change log lock
BUILD SUCCESSFUL
Total time: 6 seconds

Теперь в моем проекте (который имеет классы, аналогичные проекту моего последнего блога 30 мая), я добавил два дополнительных класса HibernateSchemaTests и LiquibaseSchemaTests.

Вот полный список HibernateSchemaTests:

Here is the full listing of HibernateSchemaTests:

/**

*

*/

package liquibase.database.tests;


import java.util.ArrayList;

import java.util.List;


import junit.framework.TestCase;


import org.hibernate.HibernateException;

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.cfg.AnnotationConfiguration;

import org.hibernate.cfg.Configuration;

import org.hibernate.dialect.Dialect;

import org.hibernate.tool.hbm2ddl.DatabaseMetadata;


/**

* @author gabriel

*

*/

public abstract class HibernateSchemaTests extends TestCase {


private AnnotationConfiguration ac;


public void assertDatabaseSchema() throws Exception {

String[] script = generateScript();

List differences = getSignificantDifferences(script);

assertTrue(differences.toString(), differences.isEmpty());

}


private String[] generateScript() throws Exception {

// Configuration cfg = getConfiguration();

// SessionFactory sessionFactory = cfg.buildSessionFactory();

// Session session = sessionFactory.openSession();

ac = new AnnotationConfiguration().configure();

SessionFactory sessionFactory = ac.buildSessionFactory();

Session session = sessionFactory.openSession();

try {

Dialect dialect = getDatabaseDialect();

DatabaseMetadata dbm = new DatabaseMetadata(session.connection(),

dialect);


String[] existingScript = ac.generateSchemaCreationScript(dialect);


for (String s : existingScript)

System.out.println(s);


String[] script = ac.generateSchemaUpdateScript(dialect, dbm);

return script;

} finally {

session.close();

}

}


protected Dialect getDatabaseDialect() throws Exception {

return (Dialect) Class.forName(

getConfiguration().getProperty("hibernate.dialect"))

.newInstance();

}


private List getSignificantDifferences(String[] script) {

List differences = new ArrayList();

for (int i = 0; i < script.length; i++) {

String line = script[i];

if (line.indexOf("add constraint") == -1)

differences.add(line);

}

return differences;

}


protected Configuration getConfiguration() throws HibernateException {

return ac;

}

}

Now we have the listing of LiquibaseSchemaTests:

/**

*

*/

package liquibase.database.tests;


/**

* @author gabriel

*

*/

public class LiquibaseSchemaTest extends HibernateSchemaTests {


/**

*

*/

public LiquibaseSchemaTest() {

// TODO Auto-generated constructor stub

}


public void test() throws Exception {

assertDatabaseSchema();

}


}

Теперь запуск этих тестов может также дать нам diff-log между схемой из наших файлов отображения (где мы использовали аннотации) и фактически базой данных.

Так в чем же разница между двумя методами? Хорошо, Liquibase дает вывод XML и может пометить базу данных. это с открытым исходным кодом. Использование hibernate является мощным, но только для разработчиков, а как насчет администраторов баз данных и других пользователей? Также при использовании liquibase разработчики должны поддерживать связь с администратором баз данных, чтобы обеспечить бесперебойную работу. Liquibase обладает преимуществом множества стабильных встроенных функций.

Интеграция муравьиных сценариев для liquibase в maven может дать хорошую функциональностьУлыбка

Смотрите этот пост в блоге Габриэля Джеремии Кэмпбелла:
http://gabrieljeremiahcampbell.wordpress.com/2010/06/06/liquibase-and-hibernate/