Skip to content

Hibernate

Podbrushkin edited this page Jul 6, 2023 · 2 revisions

H2 Database

Installation

  1. Download H2 zip here: https://www.h2database.com/html/download.html
  2. Extract it to ~\AppData\Local\Programs
  3. Create a shortcut for \h2\bin\h2.bat
  4. Place it to ~\AppData\Roaming\Microsoft\Windows\Start Menu Now you can easily start H2 from Start menu.

Usage

  1. Start H2 .bat or shortcut, web page will open with Generic H2 (Embedded) preset active;
  2. Use JDBC url jdbc:h2:mem:test for in-memory or jdbc:h2:~/test for local storage based db;
    • If local storage is used, ~/test.mv.db file will be created and will stay there until you'll delete it;
    • ~/.h2.server.properties file will be created either way;
  3. Press Connect to start server and use database;
  4. In CMD window press CTRL+C several times to stop server.

Hibernate + JPA

This a proof of concept, it is recommended to use Maven.

  1. Choose a 6.0.0.CR2 version here: https://sourceforge.net/projects/hibernate/files/hibernate-orm/;
    • Since then Hibernate release bundle download is no longer provided, so this is the latest Hibernate version you can download as a bundle;
  2. Download hibernate-release-6.0.0.CR2.zip
  3. Extract it's .\required internal directory.
  4. Into .\required\ directory copy a h2-2.2.220.jar file as well, it is in the same directory as h2.bat file from above section. It contains H2 JDBC driver.
  5. Create .\META-INF\persistence.xml file:
<persistence xmlns="https://jakarta.ee/xml/ns/persistence" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd" 
	version="3.0">
	
	<persistence-unit name="only-unit" >
		<properties>
			<property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver" />
			<property name="jakarta.persistence.jdbc.url" value="jdbc:h2:mem:test" />
			<property name="jakarta.persistence.jdbc.user" value="sa" />
			<property name="jakarta.persistence.jdbc.password" value="" />
			
			<property name="hibernate.hbm2ddl.auto" value="create" />
		</properties>
	</persistence-unit>
</persistence>
  1. Create .\example\entity\Person.java class:
package example.entity;

import jakarta.persistence.*;
// import lombok.Data;

@Entity
//@Data 
public class Person {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer id;
	private String name;
	// add Lombok to classpath, uncomment annotation and you can remove all this:
	public Person() {}
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return String.format("Person[%s %s]", id, name);
	}
}
  1. Create .\hiberSuperTiny\Start.java class:
package example;

import jakarta.persistence.*;
import example.entity.*;

public class Start {
	
	public static void main(String[] args) {
		var emf = Persistence.createEntityManagerFactory("only-unit");
		var em = emf.createEntityManager();
		
		em.getTransaction().begin();
		var person = new Person();
		person.setName("Вася Петечкин");
		em.persist(person);
		em.getTransaction().commit();
		
		listAll(em, Person.class);
		
		var pupkin = em.find(Person.class, 1);
		pupkin.setName("Петя Васечкин");
		
		listAll(em, Person.class);
		
		em.close();
		emf.close();
	}
	
	

	public static void listAll(EntityManager em, Class entity) {
		String entityName = entity.getSimpleName();
		String queryString = String.format("SELECT e FROM %s e", entityName);

		Query query = em.createQuery(queryString);
		var resultList = query.getResultList();
		System.out.printf("All records(%s):%n", resultList.size());
		for (Object obj : resultList) {
			System.out.println(obj);
		}
	}
}
  1. Compile and run it from Powershell:
javac --% -cp .;required\*;.\classes -d classes example\entity\*.java example\*.java
java --% -cp .;required\*;.\classes example.Start

Hibernate + hibernate.properties

  1. Create Person and Start classes as in the previous section;
  2. Create .\hibernate.properties:
hibernate.connection.driver_class org.h2.Driver
hibernate.connection.username sa
hibernate.connection.password
hibernate.connection.url jdbc:h2:mem:test
hibernate.hbm2ddl.auto create
  1. Replace main() method with this:
import org.hibernate.cfg.Configuration;
public static void main(String[] args) {
	var configuration = new Configuration().addAnnotatedClass(Person.class);
	var sessionFactory = configuration.buildSessionFactory();
	var em = sessionFactory.openSession();
   
	em.getTransaction().begin();
	var person = new Person();
	person.setName("Вася Петечкин");
	em.persist(person);
	em.getTransaction().commit();
	
	listAll(em, Person.class);
	
	var pupkin = em.find(Person.class, 1);
	pupkin.setName("Петя Васечкин");
	
	listAll(em, Person.class);
	
	em.close();
}
  1. Compile and run it as in previous section.

hibernate.properties is more concise than persistence.xml, but now you must manually list all your annotated classes while creating Configuration.

Hibernate + hibernate.cfg.xml

  1. Create Person and Start classes as in the previous section;
  2. Create .\hibernate.cfg.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC 
  "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 
  "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="connection.driver_class">org.h2.Driver</property>
    <property name="connection.url">jdbc:h2:mem:test</property>
    <property name="connection.username">sa</property>
    <property name="connection.password"></property>
    <property name="hbm2ddl.auto">create</property>
	
	<!-- use <mapping> or new Configuration().addAnnotatedClass(Person.class) -->
    <mapping class="example.entity.Person" />
  </session-factory>
</hibernate-configuration>
  1. Use this main() method:
public static void main(String[] args) {
	// var configuration = new Configuration().addAnnotatedClass(Person.class).configure();
	var configuration = new Configuration().configure();
	var sessionFactory = configuration.buildSessionFactory();
	var em = sessionFactory.openSession();
	
	em.getTransaction().begin();
	var person = new Person();
	person.setName("Вася Петечкин");
	em.persist(person);
	em.getTransaction().commit();
	
	listAll(em, Person.class);
	
	var pupkin = em.find(Person.class, 1);
	pupkin.setName("Петя Васечкин");
	
	listAll(em, Person.class);
	
	em.close();
}
  1. Compile and run it as in previous section. Usage of hibernate.cfg.xml is considered to be legacy and is not recommended for new projects.

Open in VSCode

  1. Open project directory through File -> Open Folder...;
  2. In Explorer -> Java Projects -> Referenced Libraries press + sign and choose all .jar files from .\required\ directory;
  3. Now you can run this project through Ctrl+F5. In Run -> Open Configurations you will find new run configuration:
{
    "type": "java",
    "name": "Start",
    "request": "launch",
    "mainClass": "example.Start",
    "projectName": "example2023_44420544",
    "classPaths": [
        "required/*.jar",
        "classes"
    ]
}

Hibernate + Maven

Use any of the above combinations. Instead of downloading .jar files, create this .\pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>hibertinymav</artifactId>
  <version>0.1</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>18</maven.compiler.source>
    <maven.compiler.target>18</maven.compiler.target>
    <exec.mainClass>example.Start</exec.mainClass>
  </properties>

  <dependencies>

    <!-- https://mvnrepository.com/artifact/org.hibernate.orm/hibernate-core -->
    <dependency>
      <groupId>org.hibernate.orm</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>6.2.6.Final</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <version>2.1.214</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.28</version>
      <scope>provided</scope>
    </dependency>


  </dependencies>
</project>

Run your application with mvn clean compile exec:java command. If you will need to run this goal in VSCode, add following plugin section after </dependency> tag, otherwise you may be not able to choose exec:java goal:

<build>
	<pluginManagement>
		<plugins>
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>exec-maven-plugin</artifactId>
				<version>3.1.0</version>
			</plugin>
		</plugins>
	</pluginManagement>
</build>

Maven Encoding Issue

You may encounter your application fails to output some unicode characters to console under Windows platform when you run it with Maven, even though when you execute your app with VSCode internal functionality or manually with java in CMD, characters are displayed properly. To fix this issue add this method to your main class and call it from main():

public static void changeConsoleEncodingIfNeeded() {
	var utf8 = java.nio.charset.Charset.forName("UTF-8");
	var ibm866 = java.nio.charset.Charset.forName("IBM866");
	if (System.console().charset().equals(ibm866) && 
		System.out.charset().equals(utf8)) {
			
		System.out.println("System.out encoding is going to change. Before: АБВ");
		System.setOut(new java.io.PrintStream(new java.io.FileOutputStream(java.io.FileDescriptor.out), true, ibm866));
		System.out.println("After: АБВ");
	}
}