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);