Na
parte anterior, descobrimos os recursos básicos do
Liquibase e escrevemos um exemplo básico de um aplicativo de
inicialização Spring que usa o Liquibase para inicializar o banco de dados. O código do aplicativo básico pode ser visto
aqui no GitHub . Neste artigo, falaremos sobre o
liquibase-maven-plugin e os recursos adicionais que ele fornece para a versão da estrutura do banco de dados. Vamos começar com como criar scripts automaticamente usando
a função de comparação .
Suponha que precisássemos fazer algumas alterações na estrutura do nosso banco de dados. Por exemplo, queremos que o
email não seja
nulo . Obviamente, para uma alteração tão pequena, você pode corrigir manualmente o código e os scripts, mas e se houver mais alterações? Nesse caso, a capacidade de comparar o banco de dados incorporado ao Liquibase será útil. Uma característica interessante é que você pode comparar não apenas dois bancos de dados, mas também um banco de dados com um conjunto de entidades JPA em nosso aplicativo. É exatamente o que faremos agora!
Crie um script com alterações usando liquibase-diff
Na seção de
plugins do arquivo
pom.xml , adicionamos esse design bastante complicado. É o
liquibase-maven-plugin , ao qual uma dependência está conectada para analisar
entidades de hibernação e trabalhar com arquivos YAML. O plug-in nos ajudará a gerar automaticamente
scripts liquibase comparando estruturas em dois bancos de dados ou mesmo comparando a estrutura de dados em um banco de dados e um conjunto de entidades hiberantes em nosso aplicativo (
liquibase-hibernate5 é adicionado a isso).
<plugin> <groupId>org.liquibase</groupId> <artifactId>liquibase-maven-plugin</artifactId> <version>3.8.1</version> <configuration> <propertyFile>${project.build.outputDirectory}/liquibase-maven-plugin.properties</propertyFile> <systemProperties> <user.name>your_liquibase_username</user.name> </systemProperties> <logging>info</logging> </configuration> <dependencies> <dependency> <groupId>org.liquibase.ext</groupId> <artifactId>liquibase-hibernate5</artifactId> <version>3.6</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <version>2.2.0.RELEASE</version> </dependency> </dependencies> </plugin>
Preste atenção na configuração
user.name . É opcional, mas sem ele o Liquibase indicará nos scripts criados o nome do usuário atual do SO sob o qual o plug-in é iniciado.
As configurações do plug-in podem ser gravadas diretamente no pom.xml ou passadas como parâmetros da linha de comando ao chamar o maven, mas eu prefiro a opção com um arquivo
liquibase-maven-plugin.properties separado. Seu conteúdo será algo parecido com isto.
changeLogFile= @project.basedir@/src/main/resources/db/changelog/db.changelog-master.yaml url= jdbc:mysql://localhost:3306/geek_db?createDatabaseIfNotExist=true&allowPublicKeyRetrieval=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC username= dbusername password= dbpassword driver= com.mysql.cj.jdbc.Driver referenceUrl= hibernate:spring:ru.usharik.liquibase.demo.persist.model?dialect=org.hibernate.dialect.MySQLDialect diffChangeLogFile= @project.basedir@/src/main/resources/db/changelog/db.changelog-@timestamp@.yaml ignoreClasspathPrefix= true
Vale a pena prestar atenção nos parâmetros
url e
referenceUrl . O script que criará o liquibase após a comparação será a diferença entre a base usando o link referenceUrl e a base usando o link
url . Se você executar posteriormente esse script na base usando o link da
URL , ele se tornará o mesmo que o localizado no link referenceUrl. Atenção especial deve ser dada ao link referenceUrl. Como você pode ver, não se refere ao banco de dados, mas ao pacote de nosso aplicativo no qual as classes de entidade estão localizadas. Graças a isso, agora podemos encontrar um script que adicionará ao banco de dados as alterações que foram feitas no código.
Agora precisamos configurar o maven-resource-plugin para substituir espaços reservados no arquivo de configurações, como
@project.basedir@
e
@timestamp@
. Para fazer isso, adicione a seção de
recursos do seguinte formulário à seção de
compilação <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> <includes> <include>*.properties</include> </includes> </resource> <resource> <directory>src/main/resources</directory> <filtering>false</filtering> <includes> <include>**/*.*</include> </includes> </resource> </resources>
A propósito, a inicialização do Spring altera o formato padrão para espaços reservados preenchidos usando o
maven-resource-plugin de
${smth}
para
@smth@
. O fato é que os espaços reservados do
@smth@
no Spring Boot são usados para substituir variáveis de ambiente e parâmetros do próprio aplicativo Spring Boot.
Além disso, alteramos ligeiramente a seção de
propriedades em
pom.xml para atribuir o valor à variável
timestamp no formato que precisamos. Infelizmente, o formato padrão pode conter caracteres proibidos nos nomes de arquivos para alguns sistemas operacionais.
<properties> <java.version>1.8</java.version> <timestamp>${maven.build.timestamp}</timestamp> <maven.build.timestamp.format>yyyyMMdd-HHmmssSSS</maven.build.timestamp.format> </properties>
Agora vamos mudar o campo de email na classe User
@Column(name = "email", nullable = false) private String email;
Por fim, execute o comando build usando
liquibase-maven-plugin para comparação.
mvn clean install liquibase:diff -DskipTests=true
Nesse caso, precisamos reconstruir completamente o projeto, porque o plugin (liquibase: diff) usará fontes não compiladas, mas arquivos de classe de entidade compilados da pasta de
destino para análise.
Se tudo for feito corretamente, após a execução bem-sucedida do comando na pasta
resources / db / changelog , você verá um arquivo com o nome
db.changelog-20190723-100748666.yaml . Devido ao fato de usarmos a data e a hora atuais no nome do arquivo, a cada lançamento, teremos um novo arquivo, o que é bastante conveniente. Se você já criou um banco de dados com a estrutura da tabela correspondente à lição anterior, o conteúdo do arquivo deve ser assim.
databaseChangeLog: - changeSet: id: 1563876485764-1 author: your_liquibase_username (generated) changes: - addNotNullConstraint: columnDataType: varchar(255) columnName: email tableName: users
Como você pode ver, esse script faz exatamente a alteração que foi feita no código. Como exercício, eu recomendaria que você execute esse script em um banco de dados vazio e observe o resultado.
Em seguida, podemos simplesmente copiar o changeSet desse arquivo para
db.changelog-master.yaml ou podemos conectar esse arquivo a ele com uma instrução
- include: file: db.changelog-20190723-100748666.yaml relativeToChangelogFile: true
Também neste arquivo, você precisa especificar
logicalFilePath: db/changelog/db.changelog-20190723-100748666.yaml
, semelhante à maneira como foi feito no
db.changelog-master.yaml .
Isso ajudará a lidar com alguns problemas possíveis ao usar o liquibase bean
embutido e o
liquibase-maven-plugin no aplicativo. Depois disso, reinicie o aplicativo ou execute o comando:
mvn liquibase:update
Vamos tentar fazer algumas alterações mais complexas no código. Por exemplo, adicione uma tabela de funções que terá um relacionamento muitos-para-muitos com a tabela do usuário.
@Entity @Table(name = "roles") public class Role implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Long id; @Column(name = "name", unique = true, nullable = false) private String name; @ManyToMany(mappedBy = "roles") private Set<User> users;
E na tabela Usuários, adicionamos
@ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "users_roles", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id")) private Set<Role> roles;
Após iniciar a comparação, obtemos um arquivo com o seguinte conteúdo
databaseChangeLog: - changeSet: id: 1563877765929-1 author: your_liquibase_username (generated) changes: - createTable: columns: - column: autoIncrement: true constraints: primaryKey: true primaryKeyName: rolesPK name: id type: BIGINT - column: constraints: nullable: false name: name type: VARCHAR(255) tableName: roles - changeSet: id: 1563877765929-2 author: your_liquibase_username (generated) changes: - createTable: columns: - column: constraints: nullable: false name: user_id type: BIGINT - column: constraints: nullable: false name: role_id type: BIGINT tableName: users_roles - changeSet: id: 1563877765929-3 author: your_liquibase_username (generated) changes: - addPrimaryKey: columnNames: user_id, role_id tableName: users_roles - changeSet: id: 1563877765929-4 author: your_liquibase_username (generated) changes: - addUniqueConstraint: columnNames: name constraintName: UC_ROLESNAME_COL tableName: roles - changeSet: id: 1563877765929-5 author: your_liquibase_username (generated) changes: - addForeignKeyConstraint: baseColumnNames: user_id baseTableName: users_roles constraintName: FK2o0jvgh89lemvvo17cbqvdxaa deferrable: false initiallyDeferred: false referencedColumnNames: id referencedTableName: users - changeSet: id: 1563877765929-6 author: your_liquibase_username (generated) changes: - addForeignKeyConstraint: baseColumnNames: role_id baseTableName: users_roles constraintName: FKj6m8fwv7oqv74fcehir1a9ffy deferrable: false initiallyDeferred: false referencedColumnNames: id referencedTableName: roles
Também podemos adicionar facilmente esse arquivo aos scripts de trabalho.
Reverter alterações
Agora vamos ver como reverter as alterações feitas. Por alguma razão, os identificadores que especificamos em changeSets não podem ser usados para reverter para eles. Existem três opções: especificar um ponto de reversão
- através do número de changeSets contados a partir do atual
- após a data da mudança
- via tag (definido usando changeSet de um tipo especial)
A tag é definida da seguinte maneira.
- changeSet: id: some_uniqui_id author: liquibase_user_name changes: - tagDatabase: tag: db_tag
Bem, os comandos para as três maneiras listadas de fazer reversão
mvn liquibase:rollback -Dliquibase.rollbackTag=db_tag mvn liquibase:rollback -Dliquibase.rollbackCount=1 mvn liquibase:rollback "-Dliquibase.rollbackDate=Jun 03, 2017"
E, finalmente, alguns materiais adicionais
- Código deste artigo
- Sobre a reversão no Liquibase
- Sobre a migração com Liquibase
- Liquibase no github
- Artigo muito bom sobre várias abordagens para versionar um banco de dados
Obviamente, terei muito gosto em comentários, acréscimos, esclarecimentos etc.