Hibernate备课笔记.docx
《Hibernate备课笔记.docx》由会员分享,可在线阅读,更多相关《Hibernate备课笔记.docx(35页珍藏版)》请在冰豆网上搜索。
Hibernate备课笔记
Hibernate笔记:
作者:
胡晟源QQ:
1312837781
1.hibernate不能删除全是非空记录表记录。
org.hibernate.PropertyValueException:
not-nullpropertyreferencesanullortransientvalue:
cn.itcast.hibernate.domain.Department.name
在hbm.xml里面写了not-null=“true”,至于什么原因,目前正在寻找。
2.Hql语句:
form+对象名。
后面的名字必须和javabean类类名相同。
3配置Myeclipse连接数据库,使之自动生成hibernate.cfg.xml和javabean类。
第一步:
成功连接数据库。
第三步:
新建一个Web工程项目。
选中该项目然后:
MyEclipse-->Project--->addHibernateCapabilities。
操作之后会出现如下界面:
选中myhibernate这个项目。
然后点击:
一:
Myeclipse
二:
projectcapabilities
三:
addHibernateCapabilities.
第二步:
第三步:
第四步:
对于这步中,我选中去掉自动生成的HibernatesessionFactory工具类,该工具类就是一个回去Session的单例。
完成后,打开项目就可以看到:
第五步:
重新回到MyEclipseDatabaseExploere界面。
选中刚刚配置的SQLServerDriver,右击选中openconnection,完成后就会出现如下界面:
第六步:
在dbo-->table中选中相应的表,右击选中HibernateReverseEngineering。
。
如上。
然后出现:
第七步:
第八步:
4.查询一列:
返回的是:
List
返回的是List
5.条件查询与占位符查询。
@Test
publicvoidtest03()
{
Sessionsession=HibernateUtils.openSession();
Transactiontransaction=session.beginTransaction();
Stringhql="fromDepartmentwherename=:
abc";
Queryquery=session.createQuery(hql).setParameter("abc","媒体部");
Listlist=query.list();
for(Departmentff:
list)
{
System.out.println(ff.getName());
}
mit();
session.close();
}
6.Criteria高级查询。
@Test
publicvoidtest04(){
Sessionsession=HibernateUtils.openSession();
Transactiontransaction=session.beginTransaction();
Criteriac=session.createCriteria(Department.class);
c.add(Restrictions.eq("name","媒体部"));
//DepartmentuniqueResult=(Department)c.uniqueResult();
Listlist=c.list();
System.out.println(list);
mit();
session.close();
}
7.主键生成策略
●(increment)并发问题。
演示并发:
给程序2次debug,第一次让程序停在点上,在运行一个debug,发现第一个成功,第二个失败。
两次debug的目的:
为了演示并发的效果,我们需要第一个程序停在某个点上等待程序第二次的运行。
●Identity标示符。
由于identity生成标识符的机制依赖于底层数据库系统,因此,要求底层数据库系统必须支持自动增长字段类型.支持自动增长字段类型的数据库包括:
DB2,Mysql,MSSQLServer,Sybase等
OID必须为long,int或short类型,如果把OID定义为byte类型,在运行时会抛出异常
●Sequence序列
●复合主键。
●派生属性。
在数据库里面定义一个字段totalPrice,formula里面的sql语句查询出来值付给totalPrice属性。
注意:
formula里面语句必须加括号().
8.MySql数据库乱码处理
Mysql乱码的解决
showvariableslike'char%';查看数据库字符集设置
client、connection、result和命令行客户端相关(windows下命令行客户端必须要设置gbk)
databaseserversystem和服务器相关字符集(system字符集不可修改)
*实际开发中建议大家将database和server字符集设置为utf8
mysql核心配置文件my.ini如果linuxf
[mysql]主要配置命令行客户端参数default-character-set=gbk----影响client、connection、result
[mysqld]配置服务器参数character-set-server=utf8-----影响databaseserver
如果服务器server字符集已经设置utf8建立数据库数据表默认utf8-----插入数据一定没有乱码
如果服务器没有设置server字符集,默认latin1,建立数据库指定字符集utf-8建表指定字符集utf-8(有乱码)
解决方案一:
设置server字符集,重新建立数据库和表
解决方案二:
jdbc:
mysql:
///db?
useUnicode=true&characterEncoding=utf-8(默认传输字符集utf8/gbk)
9.Hibernate中将PO对象分为三种状态。
●瞬时态transient尚未与HibernateSession关联对象,被认为处于瞬时状态,失去引用将被JVM回收,无持久化标识OID,未与Session关联
●持久态persistent数据库中有数据与之对应并与当前session有关联,并且相关联的session没有关闭数据库并且事务未提交存在持久化标识OID,与Session关联
●脱管态detached数据库中有数据与之对应,但当前没有session与之关联,脱管状态改变hibernate不能检测到,存在持久化标识OID,未与Session关联
自动建表:
update
Hbm文件使用type制定类型生成表如下:
CREATETABLE`book`(
`id`int(11)NOTNULLAUTO_INCREMENT,
`name`varchar(255)DEFAULTNULL,
`price`doubleDEFAULTNULL,
PRIMARYKEY(`id`)
)ENGINE=InnoDBAUTO_INCREMENT=2DEFAULTCHARSET=utf8
未使用type进行类型制定,生成表如下:
生成表和上面一样,说明这个type是与javabean类的属性类型是相关的。
与这类型无关。
程序代码
生命周期
状态
tx=session.beginTransaction();
Customerc=newCustomer();
开始生命周期
瞬时状态
Session.save(c)
处于生命周期中
转变为持久化状态
Longid=c.getId();
c=null;
Customerc2=(Customer)session.load(Customer.class,id);
mit();
处于生命周期中
处于持久化状态
session.close();
处于生命周期中
转变为脱管态
c2.getName();
处于生命周期中
处于脱管态
c2=null;
结束生命周期
结束生命周期
10.证明一级缓存存在。
@Test
publicvoidtest06()
{
Sessionsession=HibernateUtils.openSession();
Transactiontransaction=session.beginTransaction();
//证明一级缓存的存在。
Bookbook1=(Book)session.get(Book.class,1);
System.out.println(book1);
//为了证明缓存存在,重新获取一下id为1的实例。
发现其地址一样。
Bookbook2=(Book)session.get(Book.class,1);
System.out.println(book2);
mit();
session.close();
}
运行结果:
cn.itcast.hibernate.domain.Book@1397e5c
cn.itcast.hibernate.domain.Book@1397e5c
可以看出,hashcode一致。
并且2次查询只有一条select的sql语句。
●将缓存中的数据同步到数据库。
如果在上面代码中间加入session.flush();没有任何效果,输出结果,select语句全部一样。
如果使用book1.setName(“哦哦哦”);改变了其值,那么flush将会使用快照更新数据库。
●Clear清空所有缓存。
●Evit清楚指定缓存。
●证明不使用flush自动更新。
说明:
三种情况会更新数据库。
事物提交,Query查询,还有flush都会同步数据库。
●FlushMode:
设置什么时间进行一级缓存刷出。
清理缓存的模式
Session的
查询方法
tx的
commit()
Session的
flush()
FlushMode.AUTO(默认)
刷出
刷出
刷出
FlushMode.COMMIT
不刷出
刷出
刷出
FlushMode.ALWAYS
刷出
刷出
刷出
FLushMode.MANUAL
不刷出
不刷出
刷出
11.数据建表原则。
●多对多:
必须创建一张中间表,引用两张实体表主键作为外键,2个外键作为中间表的联合主键。
(非常常用重要)
学生Student和课程Course之间关系
●一个学生可以选修多门课程
一门课程可以被多名学生选修
多对多和一对多重要区别:
多对多种没有父子关系
●Student.hbm.xml
--多对多必须有中间关系表-->
--
name:
是Student类中关联Course对应属性集合名称
table:
生成中间表表名
-->
--当前Student对象,在中间表生成外键列列名-->
--
class:
set集合数据类型
column:
set映射目标类,生成中间表外键列列名
-->
Course.hbm.xml
--多对多-->
●测试用例一:
建表
●测试用例二:
测试保存,多对多没有父子关系,在真正的开发中不建议级联
*当两个持久对象,建立关系,在关系表插入一条数据(防止重复数据:
1)inverse=true使一端放弃外键维护2)不要建立双向关系)
●测试用例三:
解决学生和课程关系,产生一条delete语句
●测试用例四:
将1号学生选修1号课程,改为2号学生选修1号课程
●测试用例五:
删除一个选过课的学生
*不用级联,删除学生后,选课记录自动删除
多对多删除离线对象---cascade无效
多对多删除持久对象---cascade生效
一对多:
在多方表引入一方表作为外键。
一对一:
在任意一方引入对方主键作为外键。
12.一对多关联映射。
在多方表引入一方表作为外键。
注意配置的相互关联性:
测试类:
注意:
测试类没有添加配置文件级联操作,一旦session.save()少保存一个对象,那么就会出错。
@Test
publicvoidtest07()
{
Sessionsession=HibernateUtils.openSession();
Transactiontransaction=session.beginTransaction();
Customercustomer=newCustomer();
customer.setAge(19);
customer.setName("maechl");
Orderorder1=newOrder();
order1.setAddr("ooo");
order1.setTotalPrice(23d);
Orderorder2=newOrder();
order2.setAddr("lplpl");
order2.setTotalPrice(767d);
customer.getOrders().add(order1);
customer.getOrders().add(order2);
order1.setCustomer(customer);
order2.setCustomer(customer);
session.save(customer);
session.save(order1);
session.save(order2);
mit();
session.close();}
13.级联删除。
@Test
publicvoidtest08()
{
Sessionsession=HibernateUtils.openSession();
Transactiontransaction=session.beginTransaction();
Customercustomer=(Customer)session.get(Customer.class,1);
session.delete(customer);
mit();
session.close();
}
执行语句:
Hibernate:
deletefromsshdemo.orderwhereid=?
Hibernate:
deletefromsshdemo.orderwhereid=?
Hibernate:
deletefromsshdemo.customerwhereid=?
可以看出:
三条删除语句,删除所有关联关系的数据。
而且:
我们是从Customer端进行删除的,那么我们就可以在Customer端进行配置。
如果需要从Order进行删除,进行如下配置:
14.孤儿删除
✓在没有配置孤儿删除的时候:
Customercustomer=(Customer)session.get(Customer.class,2);
Orderorder=(Order)session.get(Order.class,3);
Customer.getOrders().remove(order);
使用customer移除3号订单,但是没有配置的情况下,那么将会把外键置为null空。
✓可以发现配置:
delete-orphan后:
客户的订单孤儿删除成功。
15.多余的SQL
修改订单:
把4号客户订单改为6号。
会产生2个update,这样不行,怎样才能一个update语句呢?
原则上,只需要一句update语句。
Inverse=true表示:
放弃维护外键值的权利,无法设置外键的值。
在父方设置cascade级联,
在父方设置inverse=true,表示Customer已无外键维护权利,把外键维护的权利交给Order.
Inverse和cascade是Hibernate映射中最难掌握的两个属性。
两者都在对象的关联操作中发挥作用。
1.明确inverse和cascade的作用
inverse决定是否把对对象中集合的改动反映到数据库中,所以inverse只对集合起作用,也就是只对one-to-many或many-to-many有效(因为只有这两种关联关系包含集合,而one-to-one和many-to-one只含有关系对方的一个引用)。
cascade决定是否把对对象的改动反映到数据库中,所以cascade对所有的关联关系都起作用(因为关联关系就是指对象之间的关联关系)。
2.inverse属性 :
inverse所描述的是对象之间关联关系的维护方式。
inverse只存在于集合标记的元素中 。
Hibernate提供的集合元素包括
Inverse属性的作用是:
是否将对集合对象的修改反映到数据库中。
inverse属性的默认值为false,表示对集合对象的修改会被反映到数据库中;inverse=false的为主动方,由主动方负责维护关联关系。
inverse=”true”表示对集合对象的修改不会被反映到数据库中。
为了维持两个实体类(表)的关系,而添加的一些属性,该属性可能在两个实体类(表)或者在一个独立的表里面,这个要看这双方直接的对应关系了:
这里的维护指的是当主控放进行增删改查操作时,会同时对关联关系进行对应的更新。
一对多:
该属性在多的一方。
应该在一方的设置inverse=true,多的一方设置inverse=false(多的一方也可以不设置inverse属性,因为默认值是false),这说明关联关系由多的一方来维护。
如果要一方维护关系,就会使在插入或是删除"一"方时去update"多"方的每一个与这个"一"的对象有关系的对象。
而如果让"多"方面维护关系时就不会有update操作,因为关系就是在多方的对象中的,直指插入或是删除多方对象就行了。
显然这样做的话,会减少很多操作,提高了效率。
注:
单向one-to-many关联关系中,不可以设置inverse="true",因为被控方的映射文件中没有主控方的信息。
多对多:
属性在独立表中。
inverse属性的默认值为false。
在多对多关联关系中,关系的两端inverse不能都设为false,即默认的情况是不对的,如果都设为false,在做插入操作时会导致在关系表中插入两次关系。
也不能都设为true,如果都设为true,任何操作都不会触发对关系表的操作。
因此在任意一方设置inverse=true,另一方inverse=false。
一对一:
其实是一对多的一个特例,inverse的设置也是一样的,主要还是看关联关系的属性在哪一方,这一方的inverse=false。
多对一:
也就是一对多的反过来,没什么区别。
2.cascade属性
cascade属性的作用是描述关联对象进行操作时