sessionFactory 为何是线程安全的,看了源码才知道,里面的类变量大都是final的。
session为何不线程安全,看了源码才知道,里面变量大都是transient的
[b]sessionfactory:[/b]
[b]session:[/b]
sessionfactory中
private transient boolean isClosed = false;
private transient SchemaExport schemaExport;
这两个都是提供读操作 所以无所谓线程安全 而且SF的开启 关闭 都是交给容器的,一般线程是不会改变它的,所以他里面的实例变量不会改变,isClose()确实被SF实现类提供,是暴露的,但是不是说一个类暴露了变量,那么这个类就一定是不安全的,这里所谓的安全主要是指是否能有效控制并发。而所谓并发控制首先需要明确的是边界,并发控制的边界我认为是:"从你执行‘读’到你执行‘写’这一过程中有没有其它的人‘写入’。一个暴露的变量如果从功能设计上的目的只是为了提供‘读取’的目的,那么即使暴露也不会产生任何预期的并发冲突。
之所以说要认识到Session是非线程安全的,主要是提醒大家,在自己开发的调用类中,不要将Session设置为成员变量,而是要将Session写在方法中,这样得到的Session才是因线程而异的.方法运行每个线程都有自己的栈内存 所以互补影响
另外在sping的opensessioninview环境中,
session与connection的关系,很多人认为 session不关那么connection就不会断开。这个是错误的。Session不是Connection,打开一个Session并不一定打开一个数据库连接。只有在开启事务后,连接才会打开,并在提交事务时关闭连接。当通过该Session再次开启事务时再次获取数据库连接。这样保证对数据库资源使用时间最短,同时充分享受Session一级缓存带来的便利。
Session共享的说法在“一次请求一个会话”中仅仅是请求内共享缓存;在“一次对话一个会话”中可以做到更大程度的共享,不过没有特殊应用场景和适当的理由,是不建议使用的。
根据集中查询、集中计算、集中提交的原则,如果计算很费时,就需要在一次请求过程中的Session分别进行两次的数据库事务的启动和提交,而不是一个长事务。
我觉得有些人对Spring的事务管理不满意,可能就是Spring简单的通过AOP方式在Service层面上作事务管理,无法更灵活的选择吧。
session只有当你真正需要访问数据库的时候才获取链接,然后在事务提交过后释放链接(Spring中是这样实现的)。也就是说,当你Session s=SessionFactory.openSession();的时候session并没有获得数据库链接,甚至在Query q=s.createQuery(hql)时都没有获得连接,真正获得连接是在q.list()的时候。当然还有其他时候。。。。
在spring管理下的SESSION,只要你记得提交事务,就没有问题
如果是纯hibernate,想在一个存活实际很长的线程中共享session,那么是否考虑一下当不需要连接的时候 session.disconnect()(好像有这个方法,虽然不推荐使用了)。此时session的一级缓存还在,要再次连接数据库的时候就重新获得 session。如何?
或者,用完了session就直接close
只有经过事务的配置之后hibernate的session才能被关闭,当然,关闭session还会涉及到懒加载导致在JSP页面中获取关系对象的异常,这个也有办法解决,spring提供了OpenSessionInViewFilter这个类,就是hibernate的session生命周期被延迟到执行完JSP之后才关闭
要是不在spring环境中 会怎么样?
session为何不线程安全,看了源码才知道,里面变量大都是transient的
[b]sessionfactory:[/b]
public final class SessionFactoryImpl implements SessionFactory, SessionFactoryImplementor {
private static final Logger log = LoggerFactory.getLogger(SessionFactoryImpl.class);
private static final IdentifierGenerator UUID_GENERATOR = new UUIDHexGenerator();
private final String name;
private final String uuid;
private final transient Map entityPersisters;
private final transient Map classMetadata;
private final transient Map collectionPersisters;
private final transient Map collectionMetadata;
private final transient Map collectionRolesByEntityParticipant;
private final transient Map identifierGenerators;
private final transient Map namedQueries;
private final transient Map namedSqlQueries;
private final transient Map sqlResultSetMappings;
private final transient Map filters;
private final transient Map imports;
private final transient Interceptor interceptor;
private final transient Settings settings;
private final transient Properties properties;
private transient SchemaExport schemaExport;
private final transient TransactionManager transactionManager;
private final transient QueryCache queryCache;
private final transient UpdateTimestampsCache updateTimestampsCache;
private final transient Map queryCaches;
private final transient Map allCacheRegions = new HashMap();
private final transient StatisticsImpl statistics = new StatisticsImpl(this);
private final transient EventListeners eventListeners;
private final transient CurrentSessionContext currentSessionContext;
private final transient EntityNotFoundDelegate entityNotFoundDelegate;
private final transient SQLFunctionRegistry sqlFunctionRegistry;
private final transient SessionFactoryObserver observer;
private final transient HashMap entityNameResolvers = new HashMap();
private final QueryPlanCache queryPlanCache = new QueryPlanCache( this );
private transient boolean isClosed = false;
[b]session:[/b]
public final class SessionImpl extends AbstractSessionImpl
implements EventSource, org.hibernate.classic.Session, JDBCContext.Context {
// todo : need to find a clean way to handle the "event source" role
// a seperate classs responsible for generating/dispatching events just duplicates most of the Session methods...
// passing around seperate reto interceptor, factory, actionQueue, and persistentContext is not manageable...
private static final Logger log = LoggerFactory.getLogger(SessionImpl.class);
private transient EntityMode entityMode = EntityMode.POJO;
private transient boolean autoClear; //for EJB3
private transient long timestamp;
private transient FlushMode flushMode = FlushMode.AUTO;
private transient CacheMode cacheMode = CacheMode.NORMAL;
private transient Interceptor interceptor;
private transient int dontFlushFromFind = 0;
private transient ActionQueue actionQueue;
private transient StatefulPersistenceContext persistenceContext;
private transient JDBCContext jdbcContext;
private transient EventListeners listeners;
private transient boolean flushBeforeCompletionEnabled;
private transient boolean autoCloseSessionEnabled;
private transient ConnectionReleaseMode connectionReleaseMode;
private transient String fetchProfile;
private transient Map enabledFilters = new HashMap();
private transient Session rootSession;
private transient Map childSessionsByEntityMode;
private EntityNameResolver entityNameResolver = new CoordinatingEntityNameResolver();
sessionfactory中
private transient boolean isClosed = false;
private transient SchemaExport schemaExport;
这两个都是提供读操作 所以无所谓线程安全 而且SF的开启 关闭 都是交给容器的,一般线程是不会改变它的,所以他里面的实例变量不会改变,isClose()确实被SF实现类提供,是暴露的,但是不是说一个类暴露了变量,那么这个类就一定是不安全的,这里所谓的安全主要是指是否能有效控制并发。而所谓并发控制首先需要明确的是边界,并发控制的边界我认为是:"从你执行‘读’到你执行‘写’这一过程中有没有其它的人‘写入’。一个暴露的变量如果从功能设计上的目的只是为了提供‘读取’的目的,那么即使暴露也不会产生任何预期的并发冲突。
之所以说要认识到Session是非线程安全的,主要是提醒大家,在自己开发的调用类中,不要将Session设置为成员变量,而是要将Session写在方法中,这样得到的Session才是因线程而异的.方法运行每个线程都有自己的栈内存 所以互补影响
另外在sping的opensessioninview环境中,
session与connection的关系,很多人认为 session不关那么connection就不会断开。这个是错误的。Session不是Connection,打开一个Session并不一定打开一个数据库连接。只有在开启事务后,连接才会打开,并在提交事务时关闭连接。当通过该Session再次开启事务时再次获取数据库连接。这样保证对数据库资源使用时间最短,同时充分享受Session一级缓存带来的便利。
Session共享的说法在“一次请求一个会话”中仅仅是请求内共享缓存;在“一次对话一个会话”中可以做到更大程度的共享,不过没有特殊应用场景和适当的理由,是不建议使用的。
根据集中查询、集中计算、集中提交的原则,如果计算很费时,就需要在一次请求过程中的Session分别进行两次的数据库事务的启动和提交,而不是一个长事务。
我觉得有些人对Spring的事务管理不满意,可能就是Spring简单的通过AOP方式在Service层面上作事务管理,无法更灵活的选择吧。
session只有当你真正需要访问数据库的时候才获取链接,然后在事务提交过后释放链接(Spring中是这样实现的)。也就是说,当你Session s=SessionFactory.openSession();的时候session并没有获得数据库链接,甚至在Query q=s.createQuery(hql)时都没有获得连接,真正获得连接是在q.list()的时候。当然还有其他时候。。。。
在spring管理下的SESSION,只要你记得提交事务,就没有问题
如果是纯hibernate,想在一个存活实际很长的线程中共享session,那么是否考虑一下当不需要连接的时候 session.disconnect()(好像有这个方法,虽然不推荐使用了)。此时session的一级缓存还在,要再次连接数据库的时候就重新获得 session。如何?
或者,用完了session就直接close
只有经过事务的配置之后hibernate的session才能被关闭,当然,关闭session还会涉及到懒加载导致在JSP页面中获取关系对象的异常,这个也有办法解决,spring提供了OpenSessionInViewFilter这个类,就是hibernate的session生命周期被延迟到执行完JSP之后才关闭
要是不在spring环境中 会怎么样?