在数据库中建立一张数据表,这里建立一个张新闻表(news)
CREATE TABLE news ( |
在MyEclipse中需要建立项目,并加入Hibernate框架支持。
但在这些之前,建议先在MyEclipse里建立与数据库的连接。
找到DBBrowser 右键new ,选择建立一个新的数据库连接
2、可以开始建立项目:
选择copy checkedLibrary jars to project folder
点next
加入Hibernate核心配置文件
3、生成的HibernateSessionFactory中,实现了连接池功能:
public class HibernateSessionFactory {
// 配置文件的所在位置和名称 private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
// 用来实现连接池的,该类类似Map集合。 private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>(); // Hibernate用来读取配置文件的类 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 HibernateSessionFactory() { }
/** * 取得数据库连接对象 * * @return Session * @throws HibernateException */ public static Session getSession() throws HibernateException { // 先从ThreadLocal中取得连接。 Session session = (Session) threadLocal.get();
// 如果手头没有连接,则取得一个新的连接 if (session == null || !session.isOpen()) { session = sessionFactory.openSession(); // 把取得出的连接记录到ThreadLocal中,以便下次使用。 threadLocal.set(session); }
return session; }
/** * 连接关闭的方法 * * @throws HibernateException */ public static void closeSession() throws HibernateException { Session session = (Session) threadLocal.get(); // 将ThreadLocal清空,表示当前线程已经没有连接。 threadLocal.set(null); // 连接放回到连接池 if (session != null) { session.close(); } }
public static Configuration getConfiguration() { return configuration; }
} |
4、根据表自动生成pojo和映射文件:
id generator 选择assigned:
生成的pojo对象:
public class News implements java.io.Serializable {
private Integer id; private String title; private String content; private Date pubDate; 以及getter/setter方法 |
映射文件:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <!-- News类和SUNXUN用户下的NEWS表映射. --> <class name="org.liky.pojo.News" table="NEWS" schema="SUNXUN"> <!-- 类中的Integer类型的id对应表中的主键 --> <id name="id" type="java.lang.Integer"> <!-- 表中主键字段为ID --> <column name="ID" precision="8" scale="0" /> <!-- 主键生成方式 --> <generator class="assigned" /> </id> <!-- 类中的String类型的title属性与表中的TITLE字段对应,长度是50,不允许为空 --> <property name="title" type="java.lang.String"> <column name="TITLE" length="50" not-null="true" /> </property> <property name="content" type="java.lang.String"> <column name="CONTENT" length="500" not-null="true" /> </property> <property name="pubDate" type="java.util.Date"> <column name="PUB_DATE" length="7" not-null="true" /> </property> </class> </hibernate-mapping> |
接下来写一个公共的DAO接口方法,为了方便使用:
/** * 公共接口 * * @param<K> * 主键类型 * @param<V> * Vo对象的类型 */ public interface IDAO<K, V> {
public void doCreate(V vo) throws Exception;
public void doUpdate(V vo) throws Exception;
public void doRemove(K id) throws Exception;
public List<V> findAll() throws Exception;
public V findById(K id) throws Exception;
/** * 分页查询方法 * @param pageNo 当前页号 * @param pageSize 每页记录数 * @param keyword 关键字 * @param column 查询的字段名 * @return * @throws Exception */ public List<V> findAll(int pageNo, int pageSize, String keyword, String column) throws Exception;
/** * 查询全部记录数,用来计算总页数 * @param keyword * @param column * @return * @throws Exception */ public int getAllCount(String keyword, String column) throws Exception;
} |
建立新闻的接口,继承公共接口,完成操作:
public interface INewsDAO extends IDAO<Integer, News> {
} |
建立实现类对象:
public class NewsDAOImpl implements INewsDAO {
public void doCreate(News vo) throws Exception { HibernateSessionFactory.getSession().save(vo); }
public void doRemove(Integer id) throws Exception { // 注意,使用Hibernate删除时,必须先查询对象,再删除. HibernateSessionFactory.getSession().delete(findById(id)); }
public void doUpdate(News vo) throws Exception { HibernateSessionFactory.getSession().update(vo); }
public List<News> findAll() throws Exception { // 使用HQL语句完成查询功能 // 1.HQL查询的是类,而不是表 // 2.可以不写SELECT关键字 String hql = "FROM News"; Query query = HibernateSessionFactory.getSession().createQuery(hql); return query.list(); }
public List<News> findAll(int pageNo, int pageSize, String keyword, String column) throws Exception { String hql = "FROM News AS n WHERE n." + column + " LIKE ?";
Query query = HibernateSessionFactory.getSession().createQuery(hql); query.setString(0, "%" + keyword + "%");
// 分页处理 query.setFirstResult((pageNo - 1) * pageSize); query.setMaxResults(pageSize);
return query.list(); }
public News findById(Integer id) throws Exception { // 根据主键完成查询功能,需要传入类型,以及主键值 return (News) HibernateSessionFactory.getSession().get(News.class, id); }
public int getAllCount(String keyword, String column) throws Exception { // 这里由于查询的不再是对象,因此必须写SELECT统计数量 String hql = "SELECT COUNT(n) FROM News AS n WHERE n." + column + " LIKE ?"; Query query = HibernateSessionFactory.getSession().createQuery(hql);
query.setString(0, "%" + keyword + "%");
return (Integer) query.uniqueResult(); }
} |
5、建立DAO工厂类:
public class DAOFactory {
public static INewsDAO getINewsDAOInstance() { return new NewsDAOImpl(); }
} |
编写Service层,这里随意定义几个方法:
public interface INewsService {
public void insert(News news) throws Exception;
public void delete(int id) throws Exception;
public News findById(int id) throws Exception;
// 如果要一次性返回多种类型的数据,可以使用Map集合,这样方便区分. public Map<String, Object> list(int pageNo, int pageSize, String keyword, String column) throws Exception;
} |
建立实现类
public class NewsServiceImpl implements INewsService {
public void delete(int id) throws Exception { // 加入事务处理功能 Transaction tx = HibernateSessionFactory.getSession() .beginTransaction(); try { DAOFactory.getINewsDAOInstance().doRemove(id); tx.commit(); } catch (Exception e) { e.printStackTrace(); tx.rollback(); throw e; } finally { HibernateSessionFactory.closeSession(); } }
public News findById(int id) throws Exception { News news = null; try { news = DAOFactory.getINewsDAOInstance().findById(id); } catch (Exception e) { e.printStackTrace(); throw e; } finally { HibernateSessionFactory.closeSession(); } return news; }
public void insert(News news) throws Exception { // 加入事务处理功能 Transaction tx = HibernateSessionFactory.getSession() .beginTransaction(); try { DAOFactory.getINewsDAOInstance().doCreate(news); tx.commit(); } catch (Exception e) { e.printStackTrace(); tx.rollback(); throw e; } finally { HibernateSessionFactory.closeSession(); } }
public Map<String, Object> list(int pageNo, int pageSize, String keyword, String column) throws Exception { Map<String, Object> map = new HashMap<String, Object>(); try { map.put("allNews", DAOFactory.getINewsDAOInstance().findAll(pageNo, pageSize, keyword, column)); map.put("allCount", DAOFactory.getINewsDAOInstance().getAllCount( keyword, column)); } catch (Exception e) { e.printStackTrace(); throw e; } finally { HibernateSessionFactory.closeSession(); } return map; }
} |
建立service工厂类
public class ServiceFactory {
public static INewsService getINewsServiceInstance() { return new NewsServiceImpl(); }
} |
测试时会发现,查询全部记录数方法出错,因为类型转换问题;
public int getAllCount(String keyword, String column) throws Exception { // 这里由于查询的不再是对象,因此必须写SELECT统计数量 String hql = "SELECT COUNT(n) FROM News AS n WHERE n." + column + " LIKE ?"; Query query = HibernateSessionFactory.getSession().createQuery(hql);
query.setString(0, "%" + keyword + "%");
// 手工使用拆箱方法,将Long转换为基本数据类型的int. return ((Long) query.uniqueResult()).intValue(); }
|
测试代码如下:
public class NewsServiceImplTest {
@Test public void testDelete() throws Exception { ServiceFactory.getINewsServiceInstance().delete(2); }
@Test public void testFindById() throws Exception { System.out.println(ServiceFactory.getINewsServiceInstance().findById(2) .getTitle()); }
@Test public void testInsert() throws Exception { News news = new News(3, "测试添加数据032", "测试内容023", new Date()); ServiceFactory.getINewsServiceInstance().insert(news); }
@Test public void testList() throws Exception { Map<String, Object> map = ServiceFactory.getINewsServiceInstance() .list(1, 2, "添加", "title"); System.out.println(map.get("allCount")); System.out.println(map.get("allNews"));
}
} |
6、如果想使用主键自增长功能,可以使用以下两种方式:
1) increment:
<id name="id" type="java.lang.Integer"> <!-- 表中主键字段为ID --> <column name="ID" precision="8" scale="0" /> <!-- 主键生成方式 --> <generator class="increment" /> </id> |
1) sequence:
先建立好序列
CREATE SEQUENCE news_seq; |
修改配置文件
<id name="id" type="java.lang.Integer"> <!-- 表中主键字段为ID --> <column name="ID" precision="8" scale="0" /> <!-- 主键生成方式 --> <generator class="sequence"> <param name="sequence">news_seq</param> </generator> </id> |