如何自定义实现Hibernate Session管理器?
嘿,这个需求其实就是要实现一个带并发数量限制的Hibernate Session包装器,核心是控制同时活跃的Session数量,并且拦截所有Session的操作(打开、关闭、数据库操作)。我给你梳理一下实现思路和具体代码,绝对能满足你的要求:
核心设计思路
- 装饰器模式包装Session:创建一个实现
Session接口的包装类,代理原生Hibernate Session的所有方法,这样任何对Session的操作都会经过我们的管理器。 - 并发数控制:用
Semaphore(信号量)来限制同时存在的Session数量(设为5),当没有可用Session时,新请求会自动阻塞等待,直到有Session被释放。 - 生命周期自动管理:在获取Session时自动申请许可,关闭Session时自动释放许可,无需手动处理并发控制逻辑。
具体实现代码
1. Session管理器类
这个类负责控制Session的创建和并发数,用信号量来做限流:
import org.hibernate.Session; import org.hibernate.SessionFactory; import java.util.concurrent.Semaphore; public class SessionManager { private final SessionFactory sessionFactory; private final Semaphore sessionSemaphore; // 初始化时传入Hibernate的SessionFactory,设置最大并发Session数为5 public SessionManager(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; this.sessionSemaphore = new Semaphore(5); } // 获取Session:没有可用许可时会阻塞等待 public Session getSession() throws InterruptedException { // 申请许可,达到上限时阻塞 sessionSemaphore.acquire(); // 创建原生Hibernate Session Session originalSession = sessionFactory.openSession(); // 返回包装后的Session,拦截后续所有操作 return new SessionWrapper(originalSession, this); } // 内部方法:Session关闭时释放许可 void releaseSession() { sessionSemaphore.release(); // 可选:添加监控日志,查看当前可用许可数 System.out.println("Session已释放,当前可用许可数:" + sessionSemaphore.availablePermits()); } }
2. Session包装类
这个类实现Session接口,代理原生Session的所有方法,同时拦截关闭操作来释放许可,还可以在每个操作前后添加自定义逻辑(比如日志):
import org.hibernate.Session; import org.hibernate.Transaction; import java.io.Serializable; import java.util.List; import java.util.Map; import java.util.Set; public class SessionWrapper implements Session { private final Session originalSession; private final SessionManager manager; public SessionWrapper(Session originalSession, SessionManager manager) { this.originalSession = originalSession; this.manager = manager; } // 重写close方法:先关闭原生Session,再释放许可 @Override public void close() { try { originalSession.close(); System.out.println("原生Session已关闭"); } finally { // 必须释放许可,避免信号量泄漏 manager.releaseSession(); } } // 代理事务开始方法,可添加自定义逻辑 @Override public Transaction beginTransaction() { System.out.println("开始执行数据库事务"); return originalSession.beginTransaction(); } // 代理get查询方法 @Override public <T> T get(Class<T> entityClass, Serializable id) { System.out.println("执行get查询:实体类=" + entityClass.getName() + ",ID=" + id); return originalSession.get(entityClass, id); } // 代理save保存方法 @Override public Serializable save(Object object) { System.out.println("执行save操作:实体对象=" + object.getClass().getName()); return originalSession.save(object); } // 以下需要实现Session接口的其他所有方法(比如update、delete、createQuery等) // 为了简洁这里只列出常用方法,实际项目中需要补全所有接口方法,都按照代理模式实现即可 @Override public void update(Object object) { System.out.println("执行update操作:实体对象=" + object.getClass().getName()); originalSession.update(object); } @Override public void delete(Object object) { System.out.println("执行delete操作:实体对象=" + object.getClass().getName()); originalSession.delete(object); } // 省略其他Session接口方法的实现... }
使用示例
模拟多线程环境下使用这个管理器,测试并发限制效果:
import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class TestSessionManager { public static void main(String[] args) { // 初始化Hibernate SessionFactory(假设你的hibernate.cfg.xml配置正确) SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); SessionManager sessionManager = new SessionManager(sessionFactory); // 模拟10个线程同时请求Session(最多5个同时执行) for (int i = 0; i < 10; i++) { int threadNum = i + 1; new Thread(() -> { try { System.out.println("线程" + threadNum + "尝试获取Session..."); Session session = sessionManager.getSession(); System.out.println("线程" + threadNum + "成功获取Session"); // 模拟数据库操作(休眠2秒) Thread.sleep(2000); // 提交事务并关闭Session Transaction tx = session.beginTransaction(); tx.commit(); session.close(); System.out.println("线程" + threadNum + "已释放Session"); } catch (InterruptedException e) { Thread.currentThread().interrupt(); e.printStackTrace(); } }).start(); } } }
关键注意事项
- Session线程安全:Hibernate Session本身是非线程安全的,所以每个线程必须独立获取自己的Session,绝对不能跨线程复用Session。
- 信号量泄漏:必须确保Session的
close()方法被调用(即使发生异常),所以在SessionWrapper的close()方法中用了finally块来保证许可被释放。 - 自定义扩展:你可以在
SessionWrapper的任何方法中添加自己的逻辑,比如操作日志、性能监控、权限校验等,完全满足“每次操作Session都会被调用”的需求。
内容的提问来源于stack exchange,提问作者Mohit Sharma
相关产品推荐
相关产品推荐

