Hibernate知识整理3

来源:互联网 发布:穿越火线自动开枪源码 编辑:程序博客网 时间:2024/06/05 00:36

问题:
1,DAO里面各个方法自己创建、关闭SessionFactory?性能会很差,因为工厂是重量级对象,重复创建工 厂的消耗很大;另外DAO中代码很多重复,工作量大。
2,事务管理主要是体现在保证多个数据操作的完整、一致,仅仅对一个操作进行事务管理,没啥意义,还 不如直接在hibernate配置文件中设为自动提交
3,session在这里直接关闭,有2个问题:A,数据缓存,session生命周期仅仅是一个DAO操作,没啥意 义。B,一个事务是基于session生命周期的,产生上面第2个问题。

问题1的解决办法
A,定义一个session工厂类:HibernateSessionFactory.java专门用于创建session工厂、获取session、关闭session、关闭session工厂。
session工厂的创建,使用单例模式,避免重复创建这个重量级对象。
B,定义一个DAO父类:BaseHibernateDAO.java,向DAO提供公共方法getSession()、closeSession(Session session)
—>解决了代码重复、session工厂重复创建的问题
—>但是,问题2、3依然存在

问题2、3的解决办法
要解决问题2、3,那么,就先要了解分析清楚“Java事务、事务与session的关系、在哪里进行事务管理、在哪里获取session在哪里关闭session-即系session生命周期”

一、JDBC事务与Hibernate事务

1.通常的观念认为,事务仅与数据库相关。
一个Java应用系统,如果要操作数据库,则通过JDBC来实现的。增加、修改、删除都是通过相应方法间接来实现的,事务的控制也相应转移到Java程序代码中。因此,Java技术体系下数据库操作的事务习惯上就称为Java事务。
2.事务是为解决数据安全操作提出的,事务控制实际上就是控制数据的安全访问。
3.Java中使用事务处理,首先要求数据库支持事务。如使用MySQL的事务功能,就要求MySQL的表类型为Innodb才支持事务(表关系-外键也是需要Innodb)。否则,在Java程序中做了commit或rollback,但在数据库中根本不能生效。
4.在数据库操作中,一项事务是指由一条或多条对数据库更新的sql语句所组成的一个不可分割的工作单元。只有当事务中的所有操作都正常完成了,整个事务才能被提交到数据库,如果有一项操作没有完成,就必须撤消整个事务。

setAutoCommit(Boolean autoCommit):设置是否自动提交事务; commit();提交事务; rollback();撤消事务;

5.在hibernate中,是通过session操作数据库,其实,session里面的各种操作功能,就是对jdbc进行了封装,一个session对应着一个数据库连接,也就是说,hibernate里面的事务,也就是jdbc事务。
只不过,我们需要通过session提供的方法来进行事务管理。
6.需要在service上进行事务管理,但会出现一定的问题(懒加载)

二、线程管理

1.Tomcat等web服务器,就是一个并发服务器,基于多线程机制下设计的:一个新的客户请求,并不是启动多一个JVM进程(因为Tomcat是基于Java开发的),而是启动多一个线程。并且采用了线程池这个技术来解决大量线程创建与销毁的问题
2.Java线程是指JVM里面的线程,一个请求操作,绑定一个线程,一个线程从开始到结果返回而结束,将线程置为空闲状态,回到线程池中。
3.多线程与对象,互相之间是没有关系的
4.如何理解线程安全?
假如同时有2个线程修改静态值,即系操作同一块内存,根据Java虚拟机对内存的管理,这是安全的,不会出现同时修改,而是队列修改的。从内核层面上理解,是线程安全的;但是,从另应用/业务层面上去理解,是线程不安全的。
如果多个线程会使用或修改相同的变量数据,就会出现线程安全问题。
5.Tomcat会采用线程池技术来降低线程创建、销毁的消耗,ThreadPool默认创建了5个线程,保存在一个200个元素的线程数组中,创建时就启动了这些线程,当然在没有请求时,它们都处理“等待”状态(其实就是一个while循环,不停的等待notify)。如果有请求时,空闲线程会被唤醒执行用户的请求。


问题2、3的解决

事务管理的位置
1-1.DAO层:在DAO方法中定义事务,意义不大,因为事务管理的作用是“多个数据操作”,而DAO方法是“原子操作”,一个方法就是一个操作而已。
1-2.Service层:在service中定义事务,是最正确的一种方式,因为一个service层方法,对应着一个业务,一个业务中可能有多个数据操作,业务与业务之间,很少会需要处于同一个事务中(当然不是绝对的:两个业务方法之间可能需要调用)。
1-3.View层:在过滤器中定义事务,懒人的做法,即系针对一个线程定义事务,在一个线程中,统一使用一个事务。但是会有一个问题存在,某些业务本来不需要事务,在这种方式下,都被强迫加上了事务,结果就是效率降低。因为加了事务,数据操作效率会下降,毕竟多了一个控制。

  • 特别注意:事务不能重叠,一个线程可以有多个事务,但是,不能同时有两个事务以上,即系,事务里面不能包含事务,譬如,过滤器中启动了事务,还未关闭,在某个操作也启动了事务,并且提交了事务,过滤器中的事务就可能有问题了。

session生命周期
2-1.在DAO方法中创建新session、关闭session。Session只存活与一个DAO操作。
2-2.线程绑定:
一个活动线程,绑定一个session。Session存活与一个活动线程中。
该线程下所有操作,都先在当前线程中寻找有无存在session,如果没有,则创建新session,并与线程绑定,如果已有,无需创建,直接使用已存在的session,在线程结束时关闭session。如果在某个操作中关闭session,下一个操作将会重新创建新session并与线程绑定,而且,在线程结束时记得关闭session,即系在过滤器中关闭session。

MyHibernateUtil.java中提供的3种session获取方法(不包括session单例)

1,openSession()
直接org.hibernate.SessionFactory.openSession()方式获取新的session对象
2,getCurrentSession()
直接org.hibernate.SessionFactory.getCurrentSession()方式获取线程绑定的session对象,事务提交会自动关闭session,如果事务放在service层,那么每个service开始都要创建新session,因为每个service结束,都会关闭session。
需要在hibernate.cfg.xml中定义

<property name="hibernate.current_session_context_class">thread或jta</property>

3,getSession()
以org.hibernate.SessionFactory.openSession()方式根据【自定义线程绑定机制】获取session对象,如果要关闭需要显式调用closeSession(),不用配置配置文件(除此之外与2相同,2是官方提供的,3是自己实现的)

public class MyHibernateUtil {    private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";    private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();//自定义线程绑定    private static Configuration configuration = new Configuration();    private static org.hibernate.SessionFactory sessionFactory;    private static String configFile = CONFIG_FILE_LOCATION;    static {        try {            configuration.configure(configFile);            sessionFactory = configuration.buildSessionFactory();        } catch (Exception e) {            System.err                    .println("%%%% Error Creating SessionFactory %%%%");            e.printStackTrace();        }    }    private MyHibernateUtil() {    }    //以org.hibernate.SessionFactory.openSession()方式根据【自定义线程绑定机制】获取session对象,如果要关闭需要显式调用close    public static Session getSession() throws HibernateException {          Session session = (Session) threadLocal.get();        if (session == null || !session.isOpen()) {            if (sessionFactory == null) {                rebuildSessionFactory();            }            session = (sessionFactory != null) ? sessionFactory.openSession()                    : null;            //测试session生命周期:open session            threadLocal.set(session);        }        return session;    }    //为上述getSession()提供    public static void closeSession() throws HibernateException {        Session session = (Session) threadLocal.get();        threadLocal.set(null);        if (session != null) {            session.close();          //测试session生命周期:close session        }    }    //直接org.hibernate.SessionFactory.openSession()方式获取新的session对象,如果要关闭需要显式调用close    public static Session openSession() throws HibernateException {               return sessionFactory.openSession();    }    //为上述openSession()提供    public static void closeSession(Session session) throws HibernateException {        if (session != null) {            session.close();        }    }    //直接org.hibernate.SessionFactory.getCurrentSession()方式获取线程绑定的session对象,事务提交自动关闭session    //需在cfg配置中定义<property name="hibernate.current_session_context_class">thread或jta</property>    public static Session getCurrentSession() throws HibernateException {           return sessionFactory.getCurrentSession();    }    public static void rebuildSessionFactory() {        try {            configuration.configure(configFile);            sessionFactory = configuration.buildSessionFactory();        } catch (Exception e) {            System.err.println("%%%% Error Creating SessionFactory %%%%");            e.printStackTrace();        }    }    public static org.hibernate.SessionFactory getSessionFactory() {        return sessionFactory;    }       public static void setConfigFile(String configFile) {        MyHibernateUtil.configFile = configFile;        sessionFactory = null;    }    public static Configuration getConfiguration() {        return configuration;    }}
0 0
原创粉丝点击