科学网

 找回密码
  注册

tag 标签: Hibernate

相关帖子

版块 作者 回复/查看 最后发表

没有相关内容

相关日志

给软件学弟学妹的建议
热度 3 xdcaxy2013 2015-3-29 10:00
在IT这块主要分为,软,硬,网以及其他(互联网营销人员,美工等等)。对于男生而言,一般大家都是想往软件工程师这块走的,由于我一直是做java web这块,想给刚入大学的对java感兴趣的学弟学妹提供一下学习建议,大话不说,先说java web的三大框架,struts2,hibernate和spring,如果在研究生毕业以前你能真正弄明白这三大框架,毕业找个中级工程师职位(1W及以上)是没有问题的。 目前,我们很多同学大学录取为计算机类专业(计算机系一般分为计算机科学与技术,软件工程和网络工程三个专业方向),一般同学接到录取通知只知道这是个热门专业,具体自己的大学规划经常是模糊的,不清晰的,往往是随波逐流,等着学校开设对应课程,待入学后却发现课程相对理论,提不起学习兴趣,结合我的经验给出大家建议如下: 1,清晰的专业规划。如果你想学计算机专业,高考就一律只报计算机类专业,高考一般大家都是从三个方面进行选择,地方,学校和专业,如果励志在计算机类有所建树,就只选专业好了。 2,抓住入学前的暑假,国内很多计算机高手,以及黑客都是中学时代对计算机编程就有浓厚兴趣的。如果已经输在起跑线上,就抓住入学前的暑假,报个培训班学吧,java基础,大概两周左右可以搞定,了解开发工具(MyEclipse和Eclipse,选择一种)然后就是html,jQuery这些课程。前两个月学习这些足以。 3,第一阶段。入学后,第一门课程一般为高数这些,虽个人觉得用处不大,但也是值得学好的,毕竟考研总是要考数学的。其次就抓紧时间了解jsp,servlet的基本概念吧。对以后的struts2框架有好处。 4,找个学习“工具”,包括电脑是基本必备的(无论台式机还是笔记本),程序编的多了,你会觉得比打游戏有意思多了。其次是有个学习的资料,起步阶段推荐,尚学堂或者师哥师姐们推荐的java web视频,需包含(struts,spring,hibernate,ajax,数据库这些)视频,若周围没有搞技术的环境和资料,淘宝上买视频就好了,推荐光盘的,买个地址给你的那种,个人一般是下两次就再也懒得下的。光盘的那种,最起码会好很多。第一学期不必太急,学期末学会基本的css,html和struts框架足以,毕竟还有学校的那些课程外加学生社团等其他活动。 5,第二,三学期可以注重学习spring和hibernate框架(尤其以 h ibernate框架为重 ),struts2+ h ibernate以足以完成一套简单的web系统。这个时候再自学数据库(mysql,SOLsever和oracle选一种,在国内外公司中三种数据库都有许多公司在用),前三个学期的学习,能坚持下来,已经不易,到大二下学期,这个时候一般是各个大学课程最紧张的时候,可以利用这个学期的三个月时间自己写套简单的系统,如利用struts2+hibernate外连mysql数据库完成一套餐馆订餐系统或者成绩管理系统,在完成这个项目的过程中,会积累下很多经验,对大三的数据库,软件工程,计算机网络的学习会奠定好基础。 6,大三一开始抓住时间,学做项目,或者参加学校或者网易,360这些组织的开发者大赛,对你好处的。这三个月是非常好的项目积累期。 7,大三下开始,技术这方面我们就得放放了,最后一年全力准备考研,数学李永乐复习全书和十年考研题至少做三遍。 8,考研录取了,一般到四月底就没什么事情了,毕业设计这些没什么难度,可以自学安卓这些方面的东西,比如安卓和java web的互联,联合项目等等。学的差不多了,就去找个公司工作,注意不是实习,现在软件公司多,5-9月4个月完全可以在一家公司做两个项目,外包也好,一般公司也罢,关键是能接触到核心业务的那些,不合适的可以立马申请走人。 9,读研 读研后可以把自己学的java EE和安卓课程结合到导师项目,如老师搞数据挖掘,只需要在学点hadoop知识即可。期间可以多申请人人网,360组织的开发者大赛。和几个同学给餐馆这些做系统,中间会遇到很多问题,这是很好的发论文的题材,注意要学好英语。提高理论和实践的结核性,那些枯燥的计算机理论在实际工程项目中会很好的体现它的理论指导价值。 10,剩下的就是今后的规划了,可以申请读博,也可以毕业去企业,移动联通,华为等等。这是我在这么多年计算机学习的真实想法,觉得大家大三下以前,可以利用寒假暑假多去北京上海,深圳这些的公司实习,工作很好找,还能赚money和积累经验,有工作经验是很占优势的。
3373 次阅读|4 个评论
Hibernate操作Mysql数据库乱码问题
chengdong166 2014-6-19 08:09
Mysql数据库: 安装时选择字符集为gbk; 配置时选择字符集为gbk; 创建数据库选择字符集为utf8 create database eschool default charset utf8 collate utf8_unicode_ci; 创建表时支持中文 CREATE TABLE `xtuser` ( `id` int(10) NOT NULL, `username` varchar(50) NOT NULL, `password` varchar(50) NOT NULL, `logintime` date default NULL, `enable` int(1) default NULL, `grade` int(2) default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=gbk 上述操作后,通过client客户端可以正常insert中文。 Hibernate连接配置时勿忘加 property name=url value=jdbc:mysql://localhost:3306/sim?useUnicode=trueamp;characterEncoding=UTF-8/property 保证与数据库字符集对应。 附:查看数据库、表字符集设置命令 mysql show variables like '%chara%'; +--------------------------+---------------------------------------------------- -----------+ | Variable_name | Value | +--------------------------+---------------------------------------------------- -----------+ | character_set_client | gbk | | character_set_connection | gbk | | character_set_database | gbk | | character_set_filesystem | binary | | character_set_results | gbk | | character_set_server | gbk | | character_set_system | utf8 | | character_sets_dir | D:\Program Files (x86)\MySQL\MySQL Server 5.0\share \charsets\ | +--------------------------+---------------------------------------------------- -----------+ 8 rows in set (0.02 sec) mysql show create database sim; +----------+--------------------------------------------------------------+ | Database | Create Database | +----------+--------------------------------------------------------------+ | sim | CREATE DATABASE `sim` /*!40100 DEFAULT CHARACTER SET utf8 */ | +----------+--------------------------------------------------------------+ 1 row in set (0.06 sec) mysql show create table xtuser; ERROR 1046 (3D000): No database selected mysql use sim; Database changed mysql show create table xtuser; +--------+---------------------------------------------------------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------------------------------------------+ | Table | Create Table | +--------+---------------------------------------------------------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------------------------------------------+ | xtuser | CREATE TABLE `xtuser` ( `id` int(10) NOT NULL, `username` varchar(50) NOT NULL, `password` varchar(50) NOT NULL, `logintime` date default NULL, `enable` int(1) default NULL, `grade` int(2) default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | +--------+---------------------------------------------------------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ---------------------------------------------+ 1 row in set (0.00 sec) mysql alter table xtuser default character set gbk collate gbk_chinese_ci; Query OK, 3 rows affected (0.28 sec) Records: 3 Duplicates: 0 Warnings: 0 mysql show create table xtuser; +--------+---------------------------------------------------------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- --+ | Table | Create Table | +--------+---------------------------------------------------------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- --+ | xtuser | CREATE TABLE `xtuser` ( `id` int(10) NOT NULL, `username` varchar(50) character set utf8 NOT NULL, `password` varchar(50) character set utf8 NOT NULL, `logintime` date default NULL, `enable` int(1) default NULL, `grade` int(2) default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=gbk | +--------+---------------------------------------------------------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- --+ 1 row in set (0.00 sec)
个人分类: 数据库学习|3685 次阅读|0 个评论
[转载]Hibernate自定义主键生成器
chengdong166 2014-6-9 16:51
在HIBERNATE中,identity 、sequence 、native 是数据局提供的主键生成方式,往往也不是我们需要,而且在程序跨数据库方面也体现出不足.还有基于算法的生成方式生成出来的主键基本都是字符串的。我们现在需要一种生成方式:使用integer作为主键类型,需要自动增,支持集群.那么我们需要自定义一个我们的主键生成器才能实现了。HIBERNATE提供了接口: import org.hibernate.id.Configurable; import org.hibernate.id.IdentifierGenerator; 自定义主键生成器。 【下面代码来源于网络】 import java.io.Serializable; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.dialect.Dialect; import org.hibernate.engine.SessionImplementor; import org.hibernate.id.Configurable; import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.PersistentIdentifierGenerator; import org.hibernate.type.Type; public class IncrementGenerator implements IdentifierGenerator, Configurable { private static final Log log = LogFactory .getLog(IncrementGenerator.class); private Integer next; private String sql; public Serializable generate(SessionImplementor session, Object object) throws HibernateException { if (sql != null) { getNext(session.connection()); } return next; } public void configure(Type type, Properties params, Dialect d) throws MappingException { String table = params.getProperty(table); if (table == null) table = params.getProperty(PersistentIdentifierGenerator.TABLE); String column = params.getProperty(column); if (column == null) column = params.getProperty(PersistentIdentifierGenerator.PK); String schema = params .getProperty(PersistentIdentifierGenerator.SCHEMA); sql = select max( + column + ) from + (schema == null ? table : schema + '.' + table); log.info(sql); } private void getNext(Connection conn) throws HibernateException { try { PreparedStatement st = conn.prepareStatement(sql); ResultSet rs = st.executeQuery(); if (rs.next()) { next = new Integer(rs.getInt(1) + 1); } else { next = 1; } } catch (SQLException e) { throw new HibernateException(e); } finally { try { conn.close(); } catch (SQLException e) { throw new HibernateException(e); } } } } 配置文件为: id name=id column=ID type=integer generator class=××.××.IncrementGenerator/generator /id
个人分类: Java学习|3737 次阅读|0 个评论
Hibernate检索策略(二)
chengdong166 2013-9-15 16:26
一、一对多和多对多的关联策略 set元素的属性lazy的默认值为true,即采用延迟加载的策略。采用这种策略时,当调用Session实例的get()方法时,返回的customer对象的orders属性引用的是Hibernate为Set集合类提供的代理类PersistentSet的实例。在这个集合代理类实例中没有存放任何Orders类对象,也就是说Orders类对象的集合代理类实例未被初始化。 注:集合的代理类org.hibernate.collection.PersistentSet与持久化类不同的是,不管有没有设置延迟加载, Hibernate的各种检索方法在为Customers类对象的属性orders赋值时,orders属性总是引用PersistentSet集合代理类的实例。 那么,Orders类对象的集合代理类实例什么时候才会被初始化呢?(1) 调用这个集合代理类实例的iterator()、size()、isEmpty()或contains()方法时,执行select语句初始化;(2) 调用Hibernate.initialize(obj)显示初始化。 Customers customer = (Customers)hibernateSession.get(cls, id); Set set = customer.getOrders(); if (! Hibernate.isInitialized(set) ) { Hibernate.initialize(set); } 1. 批量检索(batch-size 分为批量延迟检索和批量立即检索,目的是减少select语句性能。 (1) 批量延迟检索 Session hibernateSession = InitSessionUtil.openSession(); Query query = hibernateSession.createQuery(FROM Customers); // 执行select * from customers,初始化N个Customers对象, // 每个对象的orders属性引用一个集合代理类实例 List list = query.list(); for (int i = 0; i list.size(); i++) { Customers customer = (Customers)list.get(i); Set set = customer.getOrders(); //执行select * from orders,初始化集合代理类实例 Iterator it = set.iterator(); while (it.hasNext()) { Orders order = (Orders)it.next(); System.out.println(order.getOrderNumber()); } } InitSessionUtil.closeSession(); 上述代码实现从数据库检索出每个客户所发出订单的订购数量,若客户表有N条记录,则会执行1 + N次select语句,显然,频繁的执行SQL语句会降低运行性能。为减少执行select语句条数,可采用批量延迟加载,即set元素中设置属性batch-size。 set name=orders inverse=true lazy=true batch-size =3 当执行到set.iterator()时,若Session的缓存中存在多余3个的集合代理类实例未被初始化,则会按顺序批量初始化3个集合代理类实例,即: select * from orders where CUSTOMER_ID in (?, ?, ?) 若不足3个集合代理类实例未被初始化,则批量初始化剩余的集合代理类实例。这样,当下次执行set.iterator()时,若集合代理类实例已被初始化,则不会再执行select语句,从而达到减少执行select语句的目的。 (2) 批量立即检索 2. 用带子查询的select语句批量初始化集合代理类实例 set元素的fetch属性可选择select(默认)和subselect。若映射文件中的set元素设置如下: set name=orders inverse=true lazy=true fetch =subselect 则当调用set.iterator()后,会执行下面子查询: select * from orders where CUSTOMER_ID in (select ID from customers) 也就是说,若Session缓存中有N个集合代理类实例,则Hibernate能够通过带子查询的select语句,批量初始化这N个集合代理类实例。 注:当fetch=subselect时不必设置batch-size;当fetch=select时可显示设置batch-size。 3. 迫切左外连接检索(fetch属性为join) set name=orders inverse=true lazy=true fetch =join 当调用Session的get()方法(总是立即检索)后,会执行left outer join查询: select * from customers left outer join orders on ID=CUSTOMER_ID where ID=? 虽然Query的list()方法和get()方法一样,总是立即检索,但前者常忽略映射文件中配置的迫切左外连接检索策略,Hibernate对于Customers对象的orders集合仍然采用延迟加载策略。 二、多对一和一对一关联的检索策略 在映射文件中,many-to-one和one-to-one分别用来设置多对一和一对一关联关系,若没有显示设置lazy属性(proxy/no-proxy/false)和fetch属性(join/select),则采用默认的延迟检索策略。如果fetch=join,则lazy属性被忽略,此时是否显示lazy属性已无意义。 1. 迫切左外连接检索(fetch=join) 若many-to-one元素的fetch属性为join,则在检索Orders对象时,对关联的Customers对象使用迫切左外连接检索策略。对于以下程序代码: Session hibernateSession = InitSessionUtil.openSession(); Orders o = (Orders)hibernateSession.get(cls, id); Customers c = o.getCustomer(); InitSessionUtil.closeSession(); 在运行hibernateSession.get(cls, id)方法时,Hibernate需要决定: (1) 类级别的检索策略:get()方法在类级别总是使用立即检索策略; (2) 与Orders多对一关联的Customers对象的检索策略取决于Orders映射文件中many-to-one元素的fetch和lazy属性,这里fetch=join,因此lazy属性是否显示已无意义,采用迫切左外连接检索策略; (3) 与Customers一对多的Orders对象的检索策略取决于Customers映射文件中的set元素的属性lazy和fetch属性。这里lazy=false,即立即检索策略。 因此,Hibernate执行以下select语句: select * from orders o inner join customers c on o.CUSTOMER_ID=c.ID where o.ID=4 select * from orders o where oCUSTOMER_ID=4 若(3)中set元素的lazy=true,则执行以下select语句: select * from orders o inner join customers c on o.CUSTOMER_ID=c.ID where o.ID=4 注意,Query的list()方法会忽略映射文件中配置的迫切左外连接检索策略。例如以下程序代码: Session hibernateSession = InitSessionUtil.openSession(); Query query = hibernateSession.createQuery(FROM Orders o); List list = query.list(); for (int i = 0, size = list.size(); i size; i++) { Orders o = (Orders)list.get(i); // o.getCustomer()返回Customers代理类实例的引用,这个代理类实例的OID由orders表中 // 的 CUSTOMER_ID决定 Customers c = o.getCustomer(); // 执行select语句,初始化Customers代理类实例 System.out.println(c.getName()); } InitSessionUtil.closeSession(); 运行query.list()方法时,执行以下select语句: select * from orders o 当第一次运行到c.getName()时,初始化Customers代理类实例,执行select语句如下: select * from customers c where c.ID=1 2. 延迟检索 如果希望检索Orders对象时,延迟检索关联的Customers对象,只要将Orders类对应的映射文件中的many-to-one的lazy和fetch属性设置为proxy和select即可。 对于一对一关联,若使用延迟加载策略,必须将one-to-one元素的属性constrained置为true,它表明Orders对象必须与一个Customers对象关联,即Orders对象的customer属性不允许为null。 3. 无代理延迟加载 如果对Orders对象的customer属性使用无代理延迟检索,需将many-to-one元素的lazy属性置为no-proxy。与延迟加载的区别在于:(1)延迟加载,可以提供更长的延迟加载Customers对象的时间;(2)无代理延迟加载,可以直接提供更加透明的持久化服务,从而避免仅提供由Hibernate生成的Customers代理类实例。 4. 批量延迟检索和批量立即检索 如果希望检索Orders对象时,批量延迟检索关联的Customers对象,可通过设置Customers类对应的映射文件class元素的batch-size属性实现。 class name=org.test.pojo.Customers table=customers batch-size =3 若many-to-one的lazy属性置为proxy,则第一次调用Customers代理类实例的属性时将会批量初始化Customers代理类实例。例如以下程序代码: Session hibernateSession = InitSessionUtil.openSession(); Query query = hibernateSession.createQuery(FROM Orders o); List list = query.list(); for (int i = 0, size = list.size(); i size; i++) { Orders o = (Orders)list.get(i); // 返回Customers代理类实例 Customers c = o.getCustomer(); // 执行select语句,初始化Customers代理类实例 System.out.println(c.getName()); } InitSessionUtil.closeSession(); 当调用c.getName时会批量初始化Session缓存中的3个Customers代理类实例。注意这里应根据实际情况确定批量检索数目,合同的批量检索数目应该控制在3-10个,若批量检索过大,延迟加载将会失去意义。
个人分类: Java学习|3326 次阅读|0 个评论
Hibernate检索策略
chengdong166 2013-9-12 22:33
一、Hibernate检索策略 1. 立即检索策略:检索一个对象时会把与之关联的对象检索出来。这种检索策略的不足之处在于:(1)需要频繁地访问数据库,影响检索性能;(2)往往多加载一些多余的对象,这会造成内存空间资源的浪费。 2. 延迟检索策略:避免加载多余的对象,防止空间资源浪费。 3. 迫切左外连接策略:利用SQL的外连接的查询功能,减少检索SQL语句的条数。 二、检索策略类型 1. 类级别:是否采用延迟检索或立即检索策略检索指定的类对象,如Session的load()和get()方法、Query的HQL语句检索类对象。 2. 关联级:是否采用延迟检索、立即检索或迫切左外连接检索策略检索对象及与之关联的其他对象。此外,延迟检索和立即检索策略都可以设置批量检索数量。 说明:类级别的延迟检索仅影响Session的load()方法,比如: 类级别采用延迟加载策略,当执行Session的load()方法时,Hibernate不会执行select语句,而是返回一个Customers 类的代理类(Hibernate采用CGLIB工具来生成持久化类的代理类)的实例,这个代理类具有以下特征: (1) 由Hibernate运行时动态生成,它扩展了Customers 类,因此具有Customers 类的所有属性和方法。 (2) 当创建Hibernate代理类实例时,仅初始化了它的OID属性,其余属性都为null。 (3) 当应用程序第一次调用Customers代理类实例时,Hibernate会初始化代理类实例,在初始化过程中执行select语句,真正从数据库中加载Customers对象的所有数据,例如: Customers c2 = (Customers)session.load(Customers.class, new Long(5)); c2.getName();//这是执行select语句 控制台打印出SQL语句为 Hibernate: select customers0_.ID as ID4_0_, customers0_.name as name4_0_ from customers customers0_ where customers0_.ID=? 当然也有例外,当应用程序访问代理类的实例的getId时,由于在创建代理类实例时OID已存在,因此Hibernate不会到数据库中查询。 // 不会执行select语句,返回id为5其它属性为null的代理类对象, Customers c2 = (Customers)session.load(Customers.class, new Long(5)); c2.getId();//也不执行sql语句 控制台未打印出SQL语句。 通过以上分析,如果仅仅是为了获取对持久化对象的引用,可以采用延迟加载;如果是为了访问持久化类对象的属性,可以采用立即检索。 三、映射文件中用于设定检索策略的几个属性 1. class元素中的lazy:true(延迟检索,默认)、false(立即检索)。 2. set元素中的属性:(1)lazy:true(延迟检索,默认)、false(立即检索)和extra(增强延迟检索);(2)fetch:select(select查询语句,默认)、subselect(带子查询的select语句)和join(迫切左外连接检索)。 3. many-to-one元素中的属性:(1)lazy:proxy(延迟检索)、no-proxy(无代理延迟检索)和false(立即检索);(2)fetch:select(select查询语句,默认)和join(迫切左外连接检索)。 4. 设置批量检索数量属性batch-size:可选值为正整数,默认值为1。仅适用于关联级的延迟检索和立即检索,合理值为3-10。在class和set元素中设置此属性。 由于映射文件配置的检索策略固定的,无法满足各种应用逻辑的动态化需求,因此Hibernate提供了以编程方式显示设定检索策略。 四、Session的get方法与load方法在检索策略的区别 1. 采用类级别延迟加载,会影响Session的load()方法的各种运行时行为 (1)装载一个在数据库中不存在的Customers对象时,若从未访问该对象的方法(除id的setter和getter方法外),则执行load()方法不会抛出异常,直到访问该对象的方法时候才会抛出: org.hibernate.ObjectNotFoundException 。 (2)若处于Session实例的生命周期内通过load()方法返回的Customers代理类对象一直未被初始化(未执行select语句),则当该对象处于游离状态时,访问该对象的属性方法(除访问代理类实例的getId()方法外)时就会抛出异常: org.hibernate.LazyInitializationException: could not initialize proxy - no Session (3)org.hibernate.Hibernate.initialize(Object)用于显示初始化Session范围内的代理类实例。 Session hibernateSession = InitSessionUtil.openSession(); Customers customer = (Customers)hibernateSession.load(cls, id); // 判断代理类实例是否已被初始化,若否则初始化代理类实例 if (!Hibernate.isInitialized(customer)) { Hibernate.initialize(customer); } InitSessionUtil.closeSession(); 这样,当customer对象处于游离状态时,仍然可以访问该对象了。 (4)访问代理类实例的getId()方法时,由于代理类的OID值已存在,无需访问数据库,因此不会初始化代理类实例。 2. 不管class元素的属性lazy设置为true或者是false,Session的get()方法及Query的list()方法在Customers类级别总是采用立即检索策略。如果在数据库中不存在该记录,则返回null。get()方法永远不会返回代理类实例。
个人分类: Java学习|3405 次阅读|0 个评论
映射一对多关联关系
chengdong166 2013-9-10 07:05
在域模型中,类与类之间最普遍的关系莫过于关联关系。在UML语言中,关联是有方向的,包括单向关系和双向关系。以客户(Customer)和订单(Order)的关系为例,一个客户能发出多个订单,而一个订单只能属于一个客户。 1. 建立多对一的单向关联关系 本节以订单与客户这种多对一的单向关联关系为例进行说明。 (1)为建立起多对一的关联关系,Order类需声明对Customer的私有变量以及其访问该变量的setter和getter方法。 private Customer customer; (2)在映射文件中通过many-to-one建立customer属性和数据库表orders的外键CUSTOMER_ID之间的映射。 many-to-one name=customer column=CUSTOMER_ID class=org.test.pojo.Customers not-null=true lazy=false / 几点说明:映射文件中的not-null属性默认值为false,若为true则表示customer属性不为null,Hibernate在运行时保存Order对象时会先检查customer属性是否为null;lazy若为false,则Hibernate从数据库中装载Order对象时会自动加载与它关联的Customer对象。 Transaction trasaction = session.beginTransaction(); Customers c = new Customers(); c.setName(chengdongOrder); Orders order = new Orders(); order.setCustomer(c); order.setOrderNumber(16); order.setPrice(10.0); session.save(order); trasaction.commit();// 自动清理缓存,执行insert操作,提交事务 运行报错: org.hibernate.PropertyValueException: not-null property references a null or transient value: org.test.pojo.Orders.customer Hibernate不会自动持久化对象order关联的临时对象c,在数据库中意味着向orders表中新增一条记录并且这条记录的外键CUSTOMER_ID为空,这显然违反了非空约束。因此该异常的根本原因在于order对象的非空属性引用了一个临时变量c。若把not-null=true去掉,则会报错: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: org.test.pojo.Customers 这也是由于表orders的外键CUSTOMER_ID不允许为null造成的。解决办法要么在session.save(order)前持久化对象c,例如: Transaction trasaction = session.beginTransaction(); Customers c = new Customers(); c.setName(chengdongOrder); Orders order = new Orders(); session.save(c);// 持久化对象c,为该对象分配唯一的OID并加入到session缓存 order.setCustomer(c); order.setOrderNumber(17); order.setPrice(10.0); session.save(order); trasaction.commit();// 自动清理缓存,执行insert操作,提交事务 要么级联保存或更新持久化对象c,cascade=save-update表明保存或更新当前对象时(即执行update语句时),会级联保存或更新与它关联的对象。 many-to-one name=customer column=CUSTOMER_ID class=org.test.pojo.Customers cascade=save-update not-null=true lazy=false / 根据业务需求,有些时候需要将customer与order建立起一对多双向关联关系。 2. 一对多双向关联关系 order与customer之间的多对一关联关系已建立,下面将建立customer与order之间的一对多的关系。 (1) Customers类中需声明接口类型的集合属性以及它的setter和getter方法。 /** * Hibernate要求在持久化类声明集合属性时,必须为接口类型. * java.util.Set|java.util.Map|java.util.List */ private Set orders = new HashSet(); (2) 在映射文件中通过set映射集合类型的orders属性。 set name=orders cascade=save-update !-- key表明ORDERS表通过外键CUSTOMER_ID引用customers表 -- key column=CUSTOMER_ID /key !-- 表明orders集合存放的是一组org.test.pojo.Orders类对象 -- one-to-many class=org.test.pojo.Orders/ /set 几点说明: Transaction trasaction = session.beginTransaction(); Customers c = new Customers(); c.setName(chengdong1); Orders order = new Orders(); order.setOrderNumber(1); order.setPrice(1.0); // 建立Customers对象与Orders对象一对多双向关联关系 order.setCustomer(c); c.getOrders().add(order); // 持久化customer对象的同时持久化与其关联的一些对象 session.save(c); // 清理缓存 trasaction.commit(); 清理缓存时打印出的SQL语句: Hibernate: insert into customers (name, ID) values (?, ?) Hibernate: insert into orders (ORDER_NUMBER, PRICE, CUSTOMER_ID, ID) values (?, ?, ?, ?) Hibernate: update orders set CUSTOMER_ID=? where ID=? trasaction.commit()时,Hibernate会自动清理缓存中的所有持久化对象,按照持久化对象的属性变化同步更新到数据库。尽管只是向数据库表中插入数据,但还是执行了update语句。重复执行多余的SQL语句显然会影响Java应用的性能。解决办法是set设置inverse=true,即, set name=orders cascade=save-update inverse=true !-- key表明ORDERS表通过外键CUSTOMER_ID引用customers表 -- key column=CUSTOMER_ID /key !-- 表明orders集合存放的是一组org.test.pojo.Orders类对象 -- one-to-many class=org.test.pojo.Orders/ /set 这样在建立customer与order之间的双向关联关系时,当Hibernate监测到持久化对象customer和order的属性均发生变化,仅按照order对象属性的变化同步更新数据库。设置inverse=true后打印的SQL语句: Hibernate: insert into customers (name, ID) values (?, ?) Hibernate: insert into orders (ORDER_NUMBER, PRICE, CUSTOMER_ID, ID) values (?, ?, ?, ?)
个人分类: Java学习|3863 次阅读|0 个评论
理解Session缓存
chengdong166 2013-9-8 14:56
1. Session缓存 为了让对象A一直处于生命周期中,要么对象A被显示引用,要么对对象A的引用保存在始终处于生命周期中的对象B中,直到对象B的生命周期结束而结束。在Session接口的实现中包含了一系列的Java集合,这些集合用于保存对持久化对象的引用,因此这些Java集合就构成了Session的缓存。 当调用Session接口的save()方法持久化一个对象时,该对象被加入到Session缓存中,以后只要Session缓存没有被清空,该对象将一直处于生命周期中。 当调用Session接口的get()方法试图装载一个持久化对象时,Session首先判断缓存中是否存在这个对象,若存在则返回,若不存在则从数据库中检索。 2. Session缓存的作用 (1) 减少访问数据库的频率。应用程序从缓存中读取持久化对象的速度显然优于从数据库中检索数据的速度。 (2) 当缓存中的持久化对象之间存在循环关联关系时,Session会保证不出现访问对象图的死循环,以及由死循环引发的JVM堆栈溢出。 (3) 保证数据库中的相关记录与缓存中的记录同步。Session在清理缓存的时,会自动进行脏数据检查(dirty-check),如果发现Session缓存中的对象与数据库中相应记录不一致,则会按最新的对象属性更新数据库。 3. 清理缓存的机制 为减少访问数据库的次数,当Session缓存中对象的属性发生变化时,并不会及时清理缓存及执行相关的SQL Update语句,而是在特定的时间点把相关的SQL合并为一条SQL语句才清理缓存。 Transaction transaction = hibernateSession.beginTransaction(); Customers c = (Customers)hibernateSession.get(Customers.class, new Long(3)); c.setName(Mike); c.setName(Jone); transaction.commit();//自动清理缓存,执行一条Update语句,提交事务 在默认情况下,Session会在以下时间点清理缓存(保证Session缓存中对象与数据库记录数据的一致性。): (1) org.hibernate.Transaction.commit():先清理缓存再提交事务; (2) 执行持久化查询操作时,如果缓存中的持久化对象的属性已发生变化,则先清理缓存以便与数据库中的记录保持同步; (3) 显示调用Session.flush()时,会清空缓存。 Transaction transaction = hibernateSession.beginTransaction(); Customers c = (Customers)hibernateSession.get(Customers.class, new Long(3)); c.setName(ChengDong); hibernateSession.flush();// 显示清理缓存,执行update语句 c.setName(Mike); transaction.commit();// 自动清理缓存,执行update语句,提交事务 注意:commit()和flush()方法区别在于:后者进行清理缓存的操作,执行一系列SQL语句,但不会提交事务;前者会先调用flush()方法,然后提交事务。提交事务也就意味着对数据库所做的 更新将永久保存下来。 除了默认的清理缓存的方式外,还可以通过Session.setFlushMode()方法显示设定清理缓存的时间点,包括FlushMode.AUTO、FlushMode.NEVER、FlushMode.COMMIT,具体用法详查资料。 4. Java对象在持久化层的状态: (1) Transient(临时状态):new语句创建、没有被持久化且不在Session缓存中。处于这种状态的对象被称为临时对象; (2) Persistent(持久化状态):已被持久化且已加入到Session缓存中。处于这种状态的对象被称为持久化对象; (3) Detached(游离状态):已被持久化,但不处于Session的缓存中。处于这种状态的对象被称为游离对象。 持久化对象的特征: (1) OID不为NULL; (2) 位于一个Session实例的缓存中; (3) 持久化对象与数据库中的相关记录对应; (4) Session在清理缓存时,会根据持久化对象的属性变化来同步更新数据库。 Session的许多方法都能使Java对象进入持久化状态: (1) save():临时对象--- 持久化对象; (2) load()/get():返回的对象总是处于持久化状态; (3) list():返回的list对象都是持久化对象; (4) update()/saveOrUpdate()/lock():游离对象---持久化对象。 Hibernate保证同一个Session实例的缓存中,数据库中的每条记录只对应唯一的持久化对象,因此来自于同一个session实例缓存中的持久化对象的引用变量必然相同,即: Session hibernateSession = sessionFactory.openSession(); Session hibernateSession2 = sessionFactory.openSession(); Transaction transaction = hibernateSession.beginTransaction(); Transaction transaction2 = hibernateSession2.beginTransaction(); Customers a = (Customers)hibernateSession.get(Customers.class, new Long(3)); Customers b = (Customers)hibernateSession.get(Customers.class, new Long(3)); Customers c = (Customers)hibernateSession2.get(Customers.class, new Long(3)); // 同一Session实例的缓存中仅存在唯一一个与数据库记录对应的持久化对象 System.out.println(a == b);// true System.out.println(a == c);// false transaction.commit(); transaction2.commit(); hibernateSession.close(); hibernateSession2.close(); 在实际应用中,应避免一个Java对象同时位于多个Session实例中缓存中,否则这会导致重复执行SQL语句,并且极易出现高并发问题。 5. Session的一些持久化操作 (1) save 该操作首先将临时对象转化为持久化对象,并加入到Session缓存中;其次根据映射文件中给定的标识符生成器,为持久化对象分配唯一一个OID。save()方法仅用来持久化临时对象,在程序中不应该把持久化对象和游离对象传给save()。 注:save()操作仅仅是将Java对象的临时状态转化为持久化状态,并未立即执行insert语句,待需要清理缓存时才会执行insert语句。如果在save()方法改变了持久化对象的属性,则在清理缓存时不仅要执行insert语句,还要执行update语句,例如: Transaction trasaction = session.beginTransaction(); Customers c = new Customers(); c.setName(testSave); session.save(c);// 此步完成对象持久化和持久化对象OID的分配 c.setName(testCache); trasaction.commit();// 自动清理缓存 控制台打印的SQL为: Hibernate: insert into customers (name, ID) values (?, ?) Hibernate: update customers set name=? where ID=? (2) Session的get()和load()方法 这两个操作都是根据OID单数据加载持久化对象。它们的不同之处在于:当数据库中不存在与OID对应的记录时,load()会直接抛出org.hibernate.ObjectNotFoundException,而get()则返回null。
个人分类: Java学习|6647 次阅读|0 个评论
Hibernate的一点学习总结
chengdong166 2013-9-5 22:45
1. 持久化类的属性为什么不用 public, 而是用 private ? 将持久化类的属性设置成 private ,可以通过设置 setter 和 getter 方法为 private 或 public 来控制属性的读取和修改访问级别权限,例如顾客的 name 属性不能修改,可通过设置 setter 方法为 private 。 2. 在关系数据库表中,使用主键来识别记录并保证每条记录的唯一性,一般用代理主键,即不具有业务含义的字段作为主键。 3. property name=name column=name type=java.lang.String/ property 的 type 属性建议用 Java 包装类型属性 , 而不用基本数据类型。因为基本数据类型无法表示 null ,而 Java 包装类型属性默认就是 null 。 4. O/R Mapping —— id 映射 id name=id column=ID type=java.lang.Long generator class=assigned / /id 主键生成器 generator 的生成方式有以下几种: (1) assigned : 自定义主键,不需要 Hibernate 干预 ( 推荐 ) ; (2) identity: 仅局限于 Mysql 、 DB2 、 SQL Server 数据库的主键自增长方式; (3) sequence :使用数据库的 sequence 机制,如 Oracle 的 sequence ; (4) uuid.hex :该方法提供了最好的数据库插入性能和数据库平台适应性 ( 推荐 ) ; (5) native :由 hibernate 根据数据库适配器的定义,自动采用 identity 、 hilo 、 sequence 中的一种方式; (6) increment :主键按数值递增,但如果多个实例同时访问同一个数据库,各自生成主键,则容易造成主键重复。 几点说明:Hibernate在执行保存或更新操作时,若持久化对象id未设值,则(1)当class=assigned 时,由于类属性id为长整型,id默认为0,因此会保存或更新第0条记录;(2)当 class=native 时,会抛出“ Caused by: java.sql.SQLException: Field 'ID' doesn't have a default value ”异常。 (3)当 class=increment 时,打印的语句为: Hibernate: select max(ID) from customers Hibernate: insert into customers (name, ID) values (?, ?) 5. 复合主键没有生成器。 composite-id key-property name=userid column=userid type=java.lang.Long/key-property key-property name=id column=id type=java.lang.Long/key-property /composite-id 复合主键的 POJO 类需要实现 equals 和 hascode 方法(由于Hibernate在持久化操作的时候,不管这两个实例的引用和其他内容是否相同,只要主键相同则认为他们是一致的,而Object对象自带的equals()方法则会因为引用的不同而返回false)。可使用 apache提供的commons-lang.jar 包覆盖这两个方法。 除此之外,commons-lang.jar还提供了利用反射重写equals和hashCode的方法。 这样,在装载复合主键的记录时,先把类对应的对象的主键值填充好,就可以session.load()出正确的记录了。 6. 单数据加载(Session.load()/get()) Load方法根据指定的实体类和id从数据库中装载确实已存在的记录,否则抛 ObjectNotFoundException 异常。Session.load() src如下: public Object load(Class theClass, Serializable id) throws HibernateException; get方法根据指定的实体类和id从数据库查询并装载一条记录,若数据不存在则返回null。 常见异常: 调用load()方法时: (1) org.hibernate.TypeMismatchException: Provided id of the wrong type. Expected: class java.lang.Long, got class java.lang.Integer :原因是传入了非期望的Long型数据,改为load(Customers.class, new Long(2));即可查出持久化对象。 (2) 纠正上一篇《Hibernate API简介》中的工具类。不然会抛出异常: Exception in thread main org.hibernate.SessionException: Session is closed! at org.hibernate.impl.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:49) at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:874) at org.hibernate.impl.SessionImpl.load(SessionImpl.java:795) at org.hibernate.impl.SessionImpl.load(SessionImpl.java:788) at testmain.HibernateTest.load(HibernateTest.java:42) 原因是关闭此次会话的同时未销毁本地线程中的此次会话实例。即:
个人分类: Java学习|6877 次阅读|0 个评论
Hibernate API简介
chengdong166 2013-9-3 22:12
一、应用程序可以直接通过Hibernate API访问数据库。Hibernate API中的接口可分为以下几类: 1. 数据库操作(增、删、改、查)接口,包括Session、Transaction、Query接口。 2. 配置Hibernate接口:Configuration。 3. 应用程序拦截内部发生的事件,并作出相关的回应。这些接口包括:Interceptor、LoadEventListener、SaveEventListener接口等。 4. 可扩展的Hibernate接口,包括UserType、CompositeUserType、IdentifierGenerator接口。 二、Hibernate核心接口 1. Configuration接口:配置Hibernate,根启动Hibernate,创建sessionFactory对象。 private static SessionFactory sessionFactory; static { sessionFactory = new Configuration().configure().buildSessionFactory(); } Hibernate应用通过Configuration实例获得对象-关系映射文件中的元数据,以及动态配置Hibernate的属性,然后创建sessionFactory实例。 2. SessionFactory接口:初始化Hibernate,充当数据存储源的代理,创建session对象。 3. Session接口:也称为持久化管理器,它提供了持久化相关的操作,如保存、更新、删除、加载和查询对象。 4. Transation:管理事务。 5. Query和Criteria接口:执行数据库查询。 配置文件的默认路径为:hibernate3\WEB-INF\classes,即和src同级
个人分类: Java学习|4843 次阅读|0 个评论

Archiver|手机版|科学网 ( 京ICP备07017567号-12 )

GMT+8, 2024-6-16 21:46

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部