10 Şubat 2019 Pazar

Envers @Audited Anotasyonu

Giriş
Şu satırı dahil ederiz.
import org.hibernate.envers.Audited;
Örnek
Şöyle yaparız.
@Audited
@Entity
public class MyTable {
...
}
Denetim bilgisi için iki tablo yaratırız. Şöyle yaparız. MY_TABLE_AUD id + rev bilgisini içerir.
CREATE TABLE MY_TABLE_AUD (
    ID BIGINT       NOT NULL,
    REV             INTEGER NOT NULL,
    REVTYPE         TINYINT,
   PRIMARY KEY ( id, REV )
);

create table REVINFO (
    REV  INTEGER GENERATED BY DEFAULT AS IDENTITY,
    REVTSTMP BIGINT,
    PRIMARY KEY ( REV )
);

alter table MY_TABLE_AUD
   add constraint FK5ecvi1a0ykunrriib7j28vpdj
   foreign key (REV)
   references REVINFO;
withModifiedFlag Alanı
Örnek
Elimizde şöyle bir kod olsun.
@Entity
@Audited(withModifiedFlag = true)
public class Person {
  @Id
  @GeneratedValue
  private Integer id;
  private String name;
}
Şöyle bir tablo yaratılır.
+----+------+----------+-----+---------+
| ID | name | name_MOD | REV | REVTYPE |
+----+------+----------+-----+---------+

Envers AuditReader Arayüzü

Giriş
Açıklaması şöyle.
I know that envars can store changes in db and let me extract them later with AuditReader

EmptyInterceptor Sınıfı

Giriş
Elimizde şöyle bir kod olsun
@Entity
@Audited
public class Person {
    @Id
    @GeneratedValue
    private int id;

    private String name;
    private String surname;
// add getters, setters, constructors, equals and hashCode here
}
Bu nesneyi veritabanına yazalım
Person p1 = new Person("name-1", "surname-1");
personRepository.save(p1);
Person p2 = personRepository.findOne(1L);
p2.setName("new-name");
personRepository.save(p2);
Eğer EmptyInterceptor sınıfını kullanırsak değişkliklere erişebiliriz. Açıklaması şöyle.
You could write a custom interceptor by implementing org.hibernate.EmptyInterceptor. This has callbacks to update/insert/delete with old and new snapshots of entities
onSave metodu
İmzası şöyle
public boolean onSave(Object entity,Serializable id,
    Object[] state,String[] propertyNames,Type[] types)

24 Ocak 2019 Perşembe

SessionFactory Arayüzü

Giriş
Şu satırı dahil ederiz.
import org.hibernate.SessionFactory;
Hibernate Session nesnesi yaratır.

Açıklaması şöyle.
A SessionFactory in Hibernate is an object that has all the configuration information on how to connect to a database.
1.A SessionFactory is immutable;
2.The behavior of a SessionFactory is controlled by the properties supplied at the configuration time;
3.Creating a SessionFactory is a slow and heavy-weight process;
4. An application usually has only a single SessionFactory;
5.The SessionFactory object is thread-safe.
SessionFactory ve Servlet
Bu nesneyi ServletContext içinde yaratmak için şöyle yaparız.
configuration.buildSessionFactory () yerine Hibernate 5 ile gelen MetadataSources sınıfı kullanılmalı
@WebListener
public class HibernateSessionFactoryListener implements ServletContextListener 
{

  public void contextDestroyed(ServletContextEvent servletContextEvent) 
  {
    SessionFactory sessionFactory = (SessionFactory) servletContextEvent
      .getServletContext().getAttribute("SessionFactory");
    if(sessionFactory != null && !sessionFactory.isClosed())
    {
      sessionFactory.close();
    }
  }

  public void contextInitialized(ServletContextEvent servletContextEvent) 
  {
    Configuration configuration = new Configuration();
    configuration.configure("hibernate.cfg.xml");
    

    ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
      .applySettings(configuration.getProperties()).build();
    
    SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
    

    servletContextEvent.getServletContext()
      .setAttribute("SessionFactory", sessionFactory);
    
    }

}
Servlet içinde şöyle yaparız.
@WebServlet("/GetEmployeeByID")

public class GetEmployeeByID extends HttpServlet 
{

  protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException 
  {
    int empId = 3; 
    
    SessionFactory sessionFactory = (SessionFactory) request.getServletContext()
      .getAttribute("SessionFactory");
    
    Session session = sessionFactory.getCurrentSession();
    
    Transaction tx = session.beginTransaction();
    
    Employee emp = (Employee) session.get(Employee.class, empId);
    tx.commit();
    ...
}
SessionFactory ve Singleton
Masaüstü uygulamarında kullanılır.

Örnek
Şöyle yaparız. Burada org.hibernate.boot.Metadata sınıfı kullanılıyor.
public class HibernateUtils {
  private static SessionFactory factory = null;

  public static SessionFactory getSessionFactory(){
    if (factory == null) {
      factory = buildSessionFactoryFromAnnotatedClasses(...);
    }
    return factory;
  }

  public static SessionFactory buildSessionFactoryFromAnnotatedClasses(String host,
    Integer port, String dbName, String protocol, String userName, String password,
    Integer minPoolSize, Integer maxPoolSize, List<Class> annotatedClassNames) {
    StandardServiceRegistry standardRegistry =
      new StandardServiceRegistryBuilder().applySettings(...).build();

      MetadataSources sources = new MetadataSources(standardRegistry);
      annotatedClassNames.forEach(sources::addAnnotatedClass);
      Metadata metaData = sources.getMetadataBuilder().build();
      return metaData.getSessionFactoryBuilder().build();
    }
}
Örnek
Şöyle yaparız. Burada Configuration sınıfının eski buildSessionFactory() metodu çağrılıyor.
public class HibernateUtil {
  private static final SessionFactory sessionFactory;

  static {
    try {
      sessionFactory = new Configuration().configure().buildSessionFactory();
    } catch (Throwable ex) {
      System.err.println("SessionFactory creation failed." + ex);
      throw new ExceptionInInitializerError(ex);
    }
  }

  private HibernateUtil() {
  }

  public static SessionFactory getSessionFactory() {
    return sessionFactory;
  }
}
constructor - AnnotationConfiguration
Şu satırı dahil ederiz.
import org.hibernate.cfg.AnnotationConfiguration;
Şöyle yaparız.
SessionFactory factory = new AnnotationConfiguration().
  configure().buildSessionFactory();
Şöyle yaparız.
SessionFactory sessionFactory = new AnnotationConfiguration().
  configure ("hibernate.cfg.xml").buildSessionFactory();
constructor - Configuration
Şu satırı dahil ederiz.
import org.hibernate.cfg.Configuration;
Örnek
Şöyle yaparız.
SessionFactory sessionFactory =new Configuration()
    .configure()
    .buildSessionFactory();
resources dizininde hibernate.cfg.xml dosyası bulunur. Dosya şöyledir.
<hibernate-configuration>
  <session-factory>
    <property name="connection.driver_class">
      com.mysql.cj.jdbc.Driver
    </property>
    <property name="connection.url">
      jdbc:mysql://localhost/experimentA
    </property>
    <property name="connection.username">root</property>
    <property name="connection.password">password</property>
    
    <property name="dialect">
      org.hibernate.dialect.MySQLDialect
    </property>
    
    <property name="cache.provider_class">
      org.hibernate.cache.NoCacheProvider
    </property>
        
    <property name="org.hibernate.flushMode">MANUAL</property>
    
    <property name="show_sql">false</property>
    <property name="format_sql">false</property>
    
    <mapping class="com.song.example.hibernate.entities.Parent" />
    <mapping class="com.song.example.hibernate.entities.Child" />
    <mapping class="com.song.example.hibernate.entities.GrandChild" />
  </session-factory>
</hibernate-configuration>
Örnek
Hibernate xml dosyası şöyledir.
<hibernate-configuration>
  <session-factory>
    <property name="show_sql">true</property>
    <property name="format_sql">true</property>
    <property name="dialect">org.hibernate.dialect.SQLiteDialect</property>
    <property name="connection.driver_class">org.sqlite.JDBC</property>
    <property name="connection.url">jdbc:sqlite:mydb.db</property>
    <property name="connection.username"></property>
    <property name="connection.password"></property>

    <property name="hibernate.hbm2ddl.auto">update</property>

    <mapping class="your mapping class"/>
  </session-factory>
</hibernate-configuration>

Örnek
Spring Boot ile şöyle yaparız. Singleton olmasına dikkat etmek gerekir.
@SpringBootApplication
@ComponentScan({ "..." })
public class ApplicationStart extends SpringBootServletInitializer {
  
  ...    
      
  @Bean
  @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
  public SessionFactory sessionFactory() {
    return new Configuration().configure().buildSessionFactory();
  }
}
Örnek
Şöyle yaparız.
sqlProps.put("hibernate.connection.driver_class", "org.h2.Driver");
sqlProps.put("hibernate.hbm2ddl.auto", "update");
sqlProps.put("hibernate.connection.url", "jdbc:h2:test;CIPHER=AES");
sqlProps.put("hibernate.connection.username", "TEST");

sqlProps.put("hibernate.connection.password", "testAES test");
sqlProps.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");

//Pooling
sqlProps.put("hibernate.c3p0.min_size", "5");
sqlProps.put("hibernate.c3p0.max_size", "20");
sqlProps.put("hibernate.c3p0.timeout", "300");
sqlProps.put("hibernate.c3p0.max_statements", "50");
sqlProps.put("hibernate.c3p0.idle_test_period", "3000");
sqlProps.put("hibernate.temp.use_jdbc_metadata_defaults", "false");

org.hibernate.cfg.Configuration cfg =
  new org.hibernate.cfg.Configuration()
    .addAnnotatedClass(Apartment.class)
    .addAnnotatedClass(Housing.class)
    .addAnnotatedClass(Landlord.class)
    .addAnnotatedClass(Tenant.class)
    .addAnnotatedClass(Transaction.class)
    .mergeProperties(sqlProps);

SessionFactory sessionFactory = cfg.buildSessionFactory();
flush metodu
Açıklaması şöyle
Must be called at the end of a unit of work, before commiting the transaction and closing the session (depending on flush-mode, Transaction.commit() calls this method).
getCurrent() ile Session nesnesini aldıysak normalde bu metodu elle çağırmaya gerek yok. openSesion() metodu ile Session nesnesini aldıysak bu metodu çağırmak lazım.

getClassMetadata metodu
Açıklaması şöyle.
Transient - an object is transient if it has just been instantiated using the new operator, and it is not associated with a Hibernate Session. It has no persistent representation in the database and no identifier value has been assigned.
Detached - a detached instance is an object that has been persistent, but its Session has been closed. The reference to the object is still valid, of course, and the detached instance might even be modified in this state.
Şöyle yaparız.
SessionFactory sb f = HibernateUtil.getSessionFactory();
ClassMetadata metadata = sf.getClassMetadata(data.getClass());

if(metadata.getIdentifier(data) == null) {
     return TRANSIENT;
}
getCurrentSession metodu
Bu metod ile openSession() her ikisi de Session nesnesi dönseler de farklı işler yaparlar.
Session s = sessionFactory().openSession();
Session s = sessionFactory().getCurrentSession()
Eğer mevcut bir session nesnesi yoksa yeni bir nesne yaratır. Açıklaması şöyle.
- It creates a new Session if not exists, else use same session which is in current hibernate context.
- You do not need to flush and close session objects, it will be automatically taken care by Hibernate internally.
- In single threaded environment it is faster than openSession.
- You need to configure additional property. "hibernate.current_session_context_class" to call getCurrentSession method, otherwise it will throw an exception.
Örnek
Şöyle yaparız.
SessionFactory factory = ...;
Session session = factory.getCurrentSession();
getSessionFactoryOptions metodu
Şöyle yaparız
sessionFactory.getSessionFactoryOptions().getJdbcBatchSize();
isClosed metodu
Şöyle yaparız.
public static SessionFactory getSessionFactory() {

  if (sessionFactory == null || sessionFactory.isClosed()) {
    sessionFactory = new Configuration()
      .configure()
      .addAnnotatedClass(Seller.class)
      .addAnnotatedClass(Book.class)
      .buildSessionFactory();
  }

  return sessionFactory;
}
openSession metodu
Açıklaması şöyle.
-It always creates new Session object.
-You need to explicitly flush and close session objects.
-In single threaded environment it is slower than getCurrentSession.
- You do not need to configure any property to call this method.
Örnek
Singleton olarak kullanmak için şöyle yaparız. Bağlantı nesnesi hiçbir zaman kapatılmaz. tx.commit() yapmak yeterli
import org.hibernate.cfg.Configuration;
import org.hibernate.Session;        
import org.hibernate.SessionFactory;

public class HibernateSession {

  static Configuration config;
  static SessionFactory sf;
  static Session session;

  public static Session getSession() {

    if(session==null){

      config=new Configuration();
      sf=config.configure().buildSessionFactory();
      session = sf.openSession();
    }

    return session;
  }
}
Örnek
Exception'ları yakalamak için şöyle yaparız.
SessionFactory sessionFactory = ...;
//auto close session after try block
try (Session session = sessionFactory.openSession()) {
  ...
}
catch (Exception e) {
  ...
}
Örnek
Bağlantıyı açıp işlemi başlatıp bağlantıyı geri vermek için şöyle yaparız.
session.flush() -> tx.commit() -> session.close() mutlaka çağrılmalı.
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();


for ( int i=0; i<100000; i++ ) {
    Customer customer = new Customer(.....);
    session.save(customer);
    if ( i % 20 == 0 ) { //20, same as the JDBC batch size
        //flush a batch of inserts and release memory:
        session.flush();
        session.clear();
    }
}

tx.commit();
session.close();
openSession - java.sql.Connection
Bu metod Hibernate 4 ile kalktı. Eskiden şöyle yapardık.
java.sql.Connection conn = datasource.getConnection();
Session session = sessionFactory.openSession(conn);