1.问题
这两天弄一个项目,连接了mysql。第一天访问数据库没问题,第二天就报错,异常如下:
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure这里只摘取一段,很是头疼。去网上查,大多是说mysql的wait_timeout缺省为8小时,mysql数据库中是28800s。如果在wait_timeout秒期间内,数据库连接一直处于等待状态,那么mysql就将该连接关闭,这时你的java应用的连接池仍然合法的持有该连接的引用。所以你第二天操作数据时,会报错。
2.解决
一开始按照网上的思路是更改mysql数据库的wait_timeout字段,最大值是24天/365天(windows/linux)。或者改mysql的配置文件——my.ini/my.cnf(windows/linux)。可是后来想了想,这样过一段时间又会报错,该怎么解决呢。于是后决定试试看hibernate,看看通过这个框架还会导致问题出现吗
3.Hibernate配置
少一个基本会出现各种各样的问题,mysql-connector千万记得。
接着在src目录下写配置文件:hibernate.cfg.xml
这里要注意url里面的值,useUnicode=true&
它与jdbc的写法不同,他需要用& 代替; 不然会报错。
接着我们建个包,在这个包里面写个pojo对应数据库字段。同时还要写个对应pojo的映射xml:
user类没什么好说的,跟自己数据库字段对应即可
这个xml具体配置如下:
class标签下面name对应的是pojo,table是表名。
id是映射的唯一标识,也就是表中的主键。要注意的是<generator>标签里的class属性。我这里写的assigned,意思是用户自定义id,即给定一个id
还有其他6个属性,感兴趣的可以百度,这里就不做介绍了。
4.写一个Util类获取Session
package com.hibernate.DBUtil; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil { private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>(); private static SessionFactory sessionFactory = null; // SessionFactory对象 static { try { Configuration cfg = new Configuration().configure(); // 加载Hibernate配置文件 sessionFactory = cfg.buildSessionFactory(); } catch (Exception e) { System.err.println("创建会话工厂失败"); e.printStackTrace(); } } // 获取Session 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; threadLocal.set(session); } return session; } /** * 重建会话工厂 */ public static void rebuildSessionFactory() { try { Configuration cfg = new Configuration().configure(); // 加载Hibernate配置文件 sessionFactory = cfg.buildSessionFactory(); } catch (Exception e) { System.err.println("创建会话工厂失败"); e.printStackTrace(); } } // 获取SessionFactory对象 public static SessionFactory getSessionFactory() { return sessionFactory; } // 关闭Session public static void closeSession() throws HibernateException { Session session = (Session) threadLocal.get(); threadLocal.set(null); if (session != null) { session.close(); // 关闭Session } } }这里有必要说一下ThreadLocal。因为session是线程不安全的,为了解决并发的问题,防止数据污染,我们在创建session时把她放进ThreadLocal里,这是一个新思路。并不像之前的加synchronized,要程序员自己在各个不同的地方加,这样会显的很烦乱。具体ThreadLocal介绍这里贴一个博客,个人觉得理解的很到位:http://blog.csdn.net/lufeng20/article/details/24314381 ThreadLocal源码内的情况也确实如他所说。
5.CRUD
上面配置好了hibernate,下面来写一些方法来操作数据库
具体方法如下:
package com.hibernate.DBUtil; import org.hibernate.Session; import com.hibernate.Entity.User; public class HibernateORM { private HibernateUtil hibernateinit = null; private Session session = null; public void insert(Object obj) { // Hibernate的持久化操作 try { session = hibernateinit.getSession(); // 获取session session.beginTransaction(); // 开启事务 session.save(obj); // 执行数据库添加操作 session.getTransaction().commit();// 事务提交 System.out.println("数据添加成功"); } catch (Exception e) { session.getTransaction().rollback(); System.out.println("数据添加失败"); e.printStackTrace(); } finally { hibernateinit.closeSession(); } } //get方法是在不确定数据库是否存在该信息的情况下获取detail public void getDetail() { try { session = hibernateinit.getSession(); User user = (User) session.get(User.class, new Integer("4")); System.out.println("用户ID:" + user.getId() + ",用户姓名:" + user.getName()); System.out.println("第一次装载对象"); User user2 = (User) session.get(User.class, new Integer("4")); System.out.println("第二次装载对象"); } catch (Exception e) { System.out.println("get()方法对象装载失败!"); e.printStackTrace(); } finally { hibernateinit.closeSession(); } } //load方法是在给定ID的情况下获取detail public void loadDetail(){ try { session = hibernateinit.getSession(); User user = new User(); session.load(user, new Integer("1")); //装载对象 System.out.println("用户ID:" + user.getId() + ",用户姓名:" + user.getName()); } catch (Exception e) { System.out.println("load()方法对象装载失败!"); e.printStackTrace(); }finally { hibernateinit.closeSession(); } } public void delete(){ try { session = hibernateinit.getSession(); session.beginTransaction(); User user = (User)session.get(User.class, new Integer("3")); session.delete(user); session.flush(); session.getTransaction().commit(); System.out.println("对象删除成功!"); } catch (Exception e) { session.getTransaction().rollback(); System.out.println("对象删除失败!"); e.printStackTrace(); }finally { hibernateinit.closeSession(); } } public void update(){ try { session = hibernateinit.getSession(); session.beginTransaction(); User user = (User) session.get(User.class, new Integer("4")); user.setName("233"); session.flush(); session.getTransaction().commit(); System.out.println("对象修改成功"); } catch (Exception e) { session.getTransaction().rollback(); System.out.println("对象修改失败"); e.printStackTrace(); }finally { hibernateinit.closeSession(); } } }简单的写了一下,这里要注意,在增删改这些操作上,要加事务,不然会报一个Transaction的错误。
最后写一个test测试一下:
自己试了里面一些方法,发现控制台输出了SQL语句和执行结果:
确实和数据库能对应起来,CRUD操作也都没有问题。
6.昨天写好这些东西后,对数据库操作了一番发现没有问题,今天看看会不会出现通过JDBC操作mysql的wait_timeout问题。结果没有出现,这个方法应该可以不通过修改mysql数据库从而解决。下面还要进行长时间观察,看看有没有这个问题,这里先做一个记录。