hibernate基础

来源:互联网 发布:wifi音频接收器 软件 编辑:程序博客网 时间:2024/06/05 22:52
ORM(Object/Relationship Mapping):对象/关系映射      写SQL语句的缺点:
1.不同的数据库使用的SQL语法不同。比如:PL/SQL(Oracle)与T/SQL(SQL Server)2.同样的功能在不同的数据库中有不同的实现方式。比如分页SQL。3.程序过分依赖SQL对程序的移植及扩展、维护等带来很大的麻烦。为了完全使用面向对象思想开发软件,需要采用一种可行ORM框架技术。
使用ORM框架技术可以使程序员彻底抛弃书写SQL的思想,完全使用面向对象的思想开发软件。Hibernate正是这样一种技术。
1.Hibernate是java领域的一个开源的ORM框架 2.Hibernate是对JDBC进行了非常轻量级的封装,实质上还是通过JDBC实现对数据库的操作 3.Hibernate在程序中的作用:持久化层,把程序中生成的对象 持久化到数据库的表中
其他主流的ORM框架技术1.MyBatis:前身就是iBatis(Apache)2.Toplink:后被Oracle收购,并重新包装为Oracle AS TopLink3.EJB:本身是JAVAEE的规范(重量级)
开发工具:Eclipse Standard Kepler插件:Hibernate Tools for Eclipse Plugins
是由JBoss推出的一个EClipse综合开发插件,该插件可以简化ORM框架Hibernate 以及JBoss Searm EJB3等的开发工作。
如何安装Hibernatetools插件:点击help--install new。。--找到安装包--安装完重启出现Hibernate文件夹即表示安装成功或者
help—>Install New SoftWare_->粘贴【http://download.jboss.org/jbosstools/neon/stable/updates/】->点击add然后等...->选择Jboss Web and Java EE Development目录下的Hibernate Tools

创建第一个Hibernate例子   
1.导入jar包(hibernate的jar包,mysql的jar包,junit4的jar包)2.创建Hibernate配置文件 3.创建持久化类 4.创建对象-关系映射文件 4.通过Hibernate API 编写访问数据库的代码
使用版本:Hibernate 4.2.4+MySQL 6.0
第一个Hibernate例子-创建Hibernate工程1)新建Java Project2)自定义jar包(自定义并导入):windows-Preference-Java -Build Path -User Libraries_: New1(hibernate-core(命名hibernate-core) _ Add External JARs) New2(Junit4 _ Add External JARs:unit-4.10.jar) New3(mysql-jdec _ Add External JARs:mysql-connector-java-5.1.7-bin.jar)3) 在工程中导入:project-Properties-Build Path -Libraries: Add Library-User Library:  勾选2)创建的三个包_finish_OK
hibernate.cfg.xml
   <session-factory>    <property name="connection.username">root</property>    <property name="connection.password">1149754829</property>    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>    <property name="connection.url">jdbc:mysql://hibernateuseUnicode=true&amp;characterEncoding=UTF-8</property>     <property name="dialect">org.hibernate.dialect.MySQLDialect</property>          <property name="show_sql">true</property><property name="format_sql">true</property><property name="hbm2ddl.auto">create</property>    </session-factory>
构造持久类的原则:
javabean的四点要求1.公有的类2.提供公有的不带参数的构造方法3.属性私有4.属性setter/getter封装
创建完数据持久类(实体类)后需要新建对象关系映射文件:新建对象关系映射文件Student.hbm.xmlNew -> other - > Hibernate -> Hibernate XML Mapping file (hbm.xml) 选择需要映射的刚创建的实体类,会将创建的字段和数据库字段进行映射。创建完对象关系映射文件后 需要在cfg.xml中配置文件声明:如<mapping resource="Student.hbm.xml" ></mapping>配置后将在初始化 Hibernate 环境时将装载User.xml 映射信息。
Hibernate5.2版本:<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>Configuration configuration = new Configuration().configure();sessionFactory = configuration.buildSessionFactory();<mapping resource="Student.hbm.xml" />junit有两个jar包:junit和hamcrest-core
Students.hbm.xml 具体如下:
对象关系映射文件Student.hbm.xml<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" ><hibernate-mapping><class name="com.szh.model.Student" table="students"><id name="id" type="int"><column name="id" /><generator class="assigned" /></id><property name="name" type="java.lang.String"><column name="name" /></property><property name="gender" type="java.lang.String"><column name="gender" /></property><property name="birthday" type="java.util.Date"><column name="birthday" /></property><property name="address" type="java.lang.String"><column name="address" /></property></class></hibernate-mapping>
使用Junit进行测试要使用到的标签:@Test:要测试的方法。@Before:初始化方法(表示在测试前会先执行before方法进行初始化)。@After:释放资源。执行次序:@before标签下的方法——>@test方法——>@after释放资源
@Before  public void init() {    // 创建配置对象       Configuration config = new Configuration().configure();    config.addClass(Student.class);    // 创建服务注册对象    ServiceRegistry serviceRegistery = new StandardServiceRegistryBuilder().applySettings(config.getProperties()).build();    // 创建会话工厂对象    sessionFactory = config.buildSessionFactory(serviceRegistery);    // 创建会话对象    session = sessionFactory.openSession();    // 开启事务    transaction = session.beginTransaction();          }  @Test  public void testSaveStudent() {    Student s = new Student(1,"张三丰","男",new Date(),"武当山");    session.save(s);  }  @After  public void destory() {    // 提交事务    transaction.commit();    // 关闭会话    session.close();    // 关闭会话工厂    sessionFactory.close();  }
hibernate4.3.x版本中 ServiceRegistryBuilder 已过时--"Deprecated.  Use StandardServiceRegistryBuilder instead",得用StandardServiceRegistryBuilder,也就是它的父类代替。太开玩乐了,儿子废了,老爸顶上!服务注册对象 这个在博客留言中我已经详细说明,调试不通可以查看hibernate博客留言ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
hibernate配置文件的常用配置
hibernate.show_sql:是否把hibernate运行时的SQL语句输出到控制台,编码阶段便于测试。hibernate.format_sql:输出到控制台的SQL语句是否进行排版,便于阅读。建议设TRUE。hbm2ddl.auto:表结构生成策略。可帮助由java代码生成数据库脚本,进而生成具体的表结构。create(表结构存在,先删除,再重新创建)|update(在原有表结构中插入)|create-drop(先创建再删除)|validate(验证表结构,如现在结构与原结构不同,则不会创建表结构)hibernate.default_schema:默认的数据库。执行SQL时,默认给所有表名加上数据库前缀hibernate.dialect:配置hibernate数据库方言,hibernate可针对特殊数据库进行优化。
hbm2ddl.auto:1.create表示每次生成新的数据表,再对数据操作2.update表示在原有旧的数据表上执行操作3.create-drop表示先创建后删除(不常用)4.validate:用现有的表结构和原来的表结构进行验证,如果不同就不创建hibernate.default_schema:给数据库表加上一个表前缀

关于session的说明:1.不建议直接使用jdbc的connection操作数据库,而是通过使用session操作数据库;2.session可以理解为操作数据库的对象;3.session与connection,是多对一的关系,每个session都有一个与之对应的connection,一个connection不同时刻可以供多个session使用;4.把对象保存到关系型数据库中需要调用session的各种方法,如:save(),update(),delete(),createQuery()等。1.Configuration对象:配置文件对象,读取hibernate配置文件xxx.cfg.xml2.SessionFactory对象:读取对象/关系映射文件 xxx.hbm.xml3.session对象:数据库链接对象,获得之后可以操作数据库。可以理解为操作数据库的对象4.Transaction:使用session操作数据库需要开启的事务
transaction简介:事务·hibernate对数据的操作都是封装在事务当中,并且默认是非自动提交的方式。 所以用session保存对象时,如果不开启事务,并且手工提交事务,对象并不会真正保存在数据库中。·如果想让hibernate想jdbc那样自动提交事务,必须调用session对象的doWork()方法,活得jdbc的connection后,设置其为自动提交事务模式。(注意:通常并不推荐这样做)--自动提交事务(注意:通常并不推荐这样做)---//不开启事务(transaction.commit()//提交事务)的方式 @Test public void testSaveStudents(){  Stusdents s= new Students(1,"ZSF",new Date(),"wudang");  session.doWork(new Work(){@Overridepublic void execute(Connection connection) throws SQLException{  connection.setAutoCommit(true);}  })  session.save(s);//保存对象进入数据库  session.flush();//强制发出SQL语句(通过SQL写入SQL) }---自动提交事务(注意:通常并不推荐这样做)---private Transaction transaction;transaction  = session.beginTransaction();//打开事务transaction.commit()//提交事务需要注意的是:在使用save()方法后并不会真正输出sql语句,需要调用flush()强制输出sql语句才可以。然后因为采用了自动提交方式(setAutoCommit(true)),数据才真正保存在数据库。

如何获得session对象 ,调用SessionFactory对象的方法:(1)openSessionion(2)getCurrentSession如果使用getCurrentSession需要在hibernate.cfg.xml文件中进行配置:如果是本地事务(jdbc事务)<property name="hibernate.current_session_context_class">thread</property>如果是全局事务(jta事务)<property name="hibernate.current_session_context_class">jta</property>openSession 每次使用都是打开一个新的session,使用完需要调用close方法关闭session;getCurrentSession 是获取当前session对象,连续使用多次时,得到的session都是同一个对象,这就是与openSession的区别之一 一般在实际开发中,往往使用getCurrentSession多,因为一般是处理同一个事务,所以在一般情况下比较少使用openSession;
前者相当于多例,后者相当于单例。前者创建的session对象要手动关闭,不关闭的话,再次创建session时,就会创建新的session,两个session的hashCode不同;后者创建的session会在事务提交后自动关闭,不需要手动关闭,再次创建的session与已关闭的session是一致的,hashCode相同。
如果你没有设置数据库连接池,那么初始连接池的大小是20,最小是1,也就是说当你启动hibernate的时候,hibernate就初始化了一个connection对象放在你的数据库连接池里面了。如果你第一次调用openSession的时候,hibernate直接就把连接池里面的connection对象给你了,但是如果你没有关闭session,那么这个connection对象就没有被释放,所以当你再次调用openSession的时候,hibernate就会创建一个新的connection对象,如果一直这样,连接池就溢出了
1,事务:事务表示一个由一系列的数据库操作组成的不可分割的逻辑单位,其中的操作要么全做要么全都不做2,JDBC事务JDBC事务由Connnection对象控制管理,也就是说,事务管理实际上是在JDBC Connection中实现。事务周期限于Connection的生命周期。3,JTA事务提供了跨数据库连接(或其他JTA资源)的事务管理能力
hbm配置文件常用设置hbm.xml配置文档<hibernate-mapping<br>schema="schemaName" //模式的名字catalog="catalogName" //目录的名称default-cascade="cassade_style" //级联风格default-access="field/property/CalssName" //访问策略default-lazy="true/false" //加载策略package="packagename" //默认包名/><class<br>name="ClassName" //对应映射的类<br>table="tableName" //对应映射数据库的表<br>batch-size="N" //抓取策略,一次抓取多少记录<br>where="condition" //条件 eg:抓取条件<br>entity-name="EntiyName" //如果需要映射多张表<br>/>//表的主键<id name="propertyName" //对应的属性type="typeName" //对应类型column="column_nam" //映射数据库中表当中字段名的名称length="length" //指定长度<generator class="generatorClass"/>//主键生成策略</id> 主键生成策略:由于使用MYSQL,着重讲解一下两个native:有底层数据库自动生成标识符assigned:手工赋值
hibernate表单操作的内容1、单一主键;2、基本类型;3、对象类型;4、组件属性;5、表单操作CRUD实例
单一主键:指表中由某一列来充当主键assigned 由java应用程序负责生成(手工赋值),主键手动赋值native 由底层数据库自动生成标识符,如果是MySQL就是increment,如果是Oracle就是sequence,等等。另外,即使手动赋值主键,也不会起作用。主键自动增长,手工赋值不起作用<generator class="native" />mysql 中为AUTO_INCREMENT PRIMARY KEYassigned 当为int时 默认0 其他默认null
hibernate映射类型、java数据类型、sql数据类型的对应关系2.时间类型在sql中用DATE表示日期,TIME表示时间,TIMESTAMP表示日期+时间而在java中用java.util.Date即可代表日期、时间或日期+时间hibernate映射类型date、time、timestamp分别对应sql的DATE、TIME、TIMESTAMPhibernate映射类型date、time、timestamp对应java的java.util.Date因此,type属性的取值使用hibernate映射类型能做到更精确的控制,使用java类型java.util.Date输出为日期+时间
date 表示日期:YYYY-MM-ddtime 表示时间:hh:mm:ss tiemstamp时间戳: yyyy-MM-dd hh:mm:ss另外,映射的数据类型设置会决定最后数据库中的类型。比如我们在Java程序中使用的是java.util.Date类型定义变量Birthday。但在映射关系的配置文档中对应的type改成date类型,那么最后保存在数据库的Birthday类型就是date,也就是YYYY-MM-dd,而非java.util.Date(或者timestamp)的YYYY-MM-dd hh:mm:ss。
CLOB类型:大文本类型;BLOB:大的二进制文件类型(如音频、视频、图片等)MySQL不支持变准SQL的CLOB类型,在MySQL智能光,用TEXT,MEDIUMTEXT以及LONGTEXT类型表示长度唱过255字节的长文本数据。
separatorCharpublic static final char separatorChar与系统有关的默认名称分隔符。此字段被初始化为包含系统属性 file.separator 值的第一个字符。在 UNIX 系统上,此字段的值为 ‘/’;在 Microsoft Windows 系统上,它为 ‘\’。separatorpublic static final String separator与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串。此字符串只包含一个字符,即 separatorChar。pathSeparatorCharpublic static final char pathSeparatorChar与系统有关的路径分隔符。此字段被初始为包含系统属性 path.separator 值的第一个字符。此字符用于分隔以路径列表 形式给定的文件序列中的文件名。在 UNIX 系统上,此字段为 ‘:’;在 Microsoft Windows 系统上,它为 ‘;’。pathSeparatorpublic static final String pathSeparator与系统有关的路径分隔符,为了方便,它被表示为一个字符串。此字符串只包含一个字符,即 pathSeparatorChar。
blob例子 对象类型
public void saveImage() throws Exception{Student s=new Student(1,"李四","男",new Date(),"北京");File f=new File("d:"+File.separator+"boy.jpg");InputStream input=new FileInputStream(f);Blob image=Hibernate.getLobCreator(session).createBlob(input, input.available());s.setImage(image);session.save(s);}public void readImage() throws Exception{Student s=(Student) session.get(Student.class, 1);Blob image=s.getImage();InputStream input=image.getBinaryStream();File f=new File("d:"+File.separator+"girl.jpg");OutputStream output=new FileOutputStream(f);byte[] buff=new byte[input.available()];input.read(buff);output.write(buff);output.close();input.close();}
组件属性:某个类对象的成员属性是一个自定义类型对象。存储在数据库中的效果和单一字段一样1. 使用Hibernate Annotation来做对象关系映射1) 添加必须包:hibernate-jpa-2.0-api-1.0.0.Final.jar2) 在实体类中添加JPA的标准注解来进行对象关系映射.注解可以添加在属性上,也可以添加在getXxx()方法之上。   a) @Entity 映射一个实体类 @Table 指定关联的表   b) @Id 映射OID   c) @GeneratedValue 指定OID的生成策略   d) @Version 映射版本号属性   e) @Column 指定属性对应的列的信息   f) @Temporal 指定日期时间的类型(TIMESTAMP,DATE,TIME)   g) 简单属性可以不用注解。默认就是@Basic   h) @Transient 指定属性不需要映射   i) 复杂属性:关联,继承,组件,联合主键,集合   3) 在Hibernate全局配置文件中使用声明映射类的方式:   <mapping class="实体类的全限定名"/>4) 使用Annotation来映射对象关系时,加载Hibernate全局配置要使用AnnotationConfiguration类5) 持久化操作与之前没有区别。2. Hibernate Annotation 基本映射3. 映射多对一 1) @ManyToOne 2) 指定关联列@JoinColumn(name="xxx_id")4. 映射一对多 1) @OneToMany  默认会使用连接表做一对多的关联 2) 添加@JoinColumn(name="xxx_id")后,就会使用外键关联,而不使用连接表了。5. 映射双向一对多 1) 在多端:    @ManyToOne 2) 在一端:    @OneToMany(mappedBy="多端的关联属性名"):----升级后-->  @OneToMany    @JoinColumn(name="外键名")
6. cascade属性:指定级联操作的行为(可多选)  CascadeType.PERSIST :调用JPA规范中的persist(),不适用于Hibernate的save()方法  CascadeType.MERGE:调用JPA规范中merge()时,不适用于Hibernate的update()方法 CascadeType.REMOVE:调用JPA规范中的remove()时,适用于Hibernate的delete()方法 CascadeType.REFRESH:调用JPA规范中的refresh()时,适用于Hibernate的flush()方法 CascadeType.ALL:JPA规范中的所有持久化方法。7. mappedBy属性:用在双向关联中,把关系的维护权反转  跟hibernate XML映射中的property-ref一样。8. cascade属性和mappedBy用在一起时,一定要通过调用双方的set方法来建立关系。10. 双向一对一 1) 基于外键   a) 在主控方:@OneToOne   b) 在被控方:@OneToOne(mappedBy="对方的关联属性名") 2) 基于主键: JPA标准中没有提供共享主键生成问题的标准方法,使用Hibernate的扩展   a) 在主控方:Car @Id @GeneratedValue(generator="my-uuid") @GenericGenerator(name="my-uuid", strategy="uuid") private String id; @OneToOne(cascade={CascadeType.ALL}) @PrimaryKeyJoinColumn private Brand brand;b) 在被控方:Brand @Id @GeneratedValue(generator="myFG") @GenericGenerator(name="myFG", strategy="foreign",parameters=@Parameter(name="property",value="car")) private String id;  @OneToOne(mappedBy="brand") private Car car;
11. 双向多对多 1. 在主控方:   //从学生到课程的多对多: 最好由某一端来维护这个关系会更有效率@ManyToMany@JoinTable(name="student_course",joinColumns={@JoinColumn(name="student_id")},inverseJoinColumns={@JoinColumn(name="course_id")})private Set<Course> courseSet = new HashSet<Course>(); 2. 在被控方:  //课程到学生的多对多@ManyToMany(mappedBy="courseSet")private Set<Student> stus = new HashSet<Student>();12. 把双向多对多拆成两个一对多: 1-->*<--113. 继承映射:1. 整个继承树一张表在父类中添加从下注解@Entity@Inheritance(strategy=InheritanceType.SINGLE_TABLE)@DiscriminatorColumn(name="type",length=3)@DiscriminatorValue("u")子类中添加以下注解@Entity@DiscriminatorValue("w")2. 每个子类一张表在父类添加如下注解@Entity@Table(name="user")@Inheritance(strategy=InheritanceType.JOINED)在子类中跟普通实体类的映射相同3. 每个具体类一张表在父类中@Entity@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)public class User {@Id@GeneratedValue(strategy=GenerationType.TABLE,generator="xxGen")@TableGenerator(name="xxGen",allocationSize=1)private Long id;...}在子类中跟普通实体类的映射相同
14. 组件映射 在组件类中用@Emabbedable在使用这个组件类中用@Emabbed@AttributeOverrides({@AttributeOverride(name="email", column=@Column(name="p_email")),@AttributeOverride(name="address", column=@Column(name="p_address")),@AttributeOverride(name="mobile", column=@Column(name="p_mobile"))})15. 联合主键映射 1. 主键类:用@Emabbedable映射。并实现Serializable接口,使用主键属性重写hashCode()和equals()方法。 2. 使用这个主键类的类中。用@Id映射。

组件属性:实体类中的某个属性属于用户自定义的类的对象    
作用:将两个实体类合并在一起组建成一个表
<component>标签表示,实体中成员变量的类型是用户自定义的类型。按hibernate的规则,基础类型使用<property>标签,而非基础类型就使用<component>标签。<component>标签中,name表示这个对象的名字,class表示这个对象是哪个用户自定义类型。其中的property是指,用户自定义类型中的成员变量。而声明了<component>的那个成员变量,在数据库中的表示方式是:这个用户自定义类型的成员变量中的成员变量,将以列的方式显示在数据库中。即有该变量有三个成员变量,那么数据库中的表就多出对应的三列。
<component name = "address" class="Address"> <property name ="postcode" column="POSTCODE"></property> <property name ="phone" column="PHONE"></property> <property name ="address" column="ADDRESS"></property></component>
单个记录查询get与load的区别1.在不考虑缓存的情况下,get方法会在调用之后立即向数据库发出sql语句,返回持久化对象。2.load方法会在调用后返回一个代理对象,该代理对象只保存了实体对象的id,直到使用对象的非主键属性时才会发出sql语句。3.查询数据库中不存在的数据时,get方法返回null,load方法抛出异常org.hibernate.ObjectNotFoundException单表的增删改查CRUD1.保存对象,save2.修改对象,update3.删除对象,delete4.查询单个记录,get/load
@Test 生成策略需要为update(create会被清空)public void testGetStudents {  Students s = (Students)session.get(Students.class,100)//使用反射得到类型+主键  System.out.printlin(s);}@Testpublic void testLoadStudents {  Students s = (Students)session.load(Students.class,100)//使用反射得到类型+主键  System.out.printlin(s);}@Testpublic void testUpdateStudents {  Students s = (Students)session.get(Students.class,100)//使用反射得到类型+主键  s.setGender("女");  session.update(s);}@Testpublic void testDeleteStudents {  Students s = (Students)session.get(Students.class,100)//使用反射得到类型+主键  session.delete(s);}

可以进行测试区分get与load区别;s.getClass().getName() get返回Students load返回代理类对象Student_$$_javassist_0.....
总结:
 
1.ORM Hibernate 对象关系映射;为了少写和底层数据库相关的sql语句,方便程序的维护、修改,提高跨平台性和可扩展性。Hibernate是Java领域内的一款技术成熟稳定的ORM框架2.Hibernate开发的基本步骤(1)编写配置文档hibernate.cfg.xml(2)编写实体类。注意:每一个实体类都要与数据库中的一张表一一对应,实体类的编写要遵循JavaBean的要求。(3)生成对应实体类的映射文件并添加到配置文档中(4)调用Hibernate API进行测试3.session类似于JDBC里面的connection对象。调用session操作数据库,实际上就是调用connection的各种API函数来实现的。4.openSession与getCurrentSession的区别openSension每次都是创建新的session对象,而getCurrentSenssion使用单例模式,每次创建都是相同的对象。openSession在使用完毕后需要显式地关闭,而getCurrentSession在事务提交之后会自动关闭。5.单表操作常用的方法增删改查对应使用session当中的save、delete、update、get/load方法6.单表操作查询一条记录时,get和load的区别get在使用的时候立即发送sql语句,并且获得的是实体类的对象类型,而load只有在使用具体对象的非主键属性的时候才会发送sql语句,而且返回的是一个代理对象。