(2)配置及用法之Hibernate
(二)配置及用法之Hibernate
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。本文讲述Hibernate2的一些配置用法等,可能本文写得不是很详细和通俗易懂,希望和大家一起讨论和学习,进入正题。
Hibernate目前用到的包:
antlr-2.7.6.jar、commons-collections-3.1.jar、dom4j-1.6.1.jar、hibernate3.jar、hibernate-jpa-2.0-api-1.0.0.Final.jar、javassist-3.12.0.GA.jar、jta-1.1.jar、slf4j-api-1.6.1.jar、slf4j-nop-1.6.1.jar
(1)hibernate.cfg.xml的配置:
Hibernate的基本应用:
配置Session:
事务封装例子:
例子用所使用的持久化类:
(2)Score.hbm.xml的配置:(student.hbm.xml不列举,我只是大概描述配置,希望具体的用法还是让大家去实践,实践出真理!)
(3)简要说明一下各xml里标签的应用:
(4)Annotation配置Hibernate:
对于基于主键的双向一对一的Annotation配置,弄不出来,希望懂的可以留言。
好了,暂且我先介绍到这里,以后会慢慢完善Hibernate的配置,注意设置延迟加载的利弊,当Lazy="true",如果关闭了Session再进行获取就会出错。当然,可以通过一些配置来解决这个问题,去网上搜索一下把。网上的资源我们得充分利用!
总结:(1)主要开发过程hibernate.cfg.xml+xxx.hbm.xml+实体类
(2)如果用Annotation配置实体类,那么xxx.hbm.xml可省略。开发模型为hibernate.cfg.xml+实体类
(3)当hibernate.hbm2ddl.auto=update不起作用时候在spring的session的sessionfactory加上: <property name="schemaUpdate">
<value>true</value>
</property>
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。本文讲述Hibernate2的一些配置用法等,可能本文写得不是很详细和通俗易懂,希望和大家一起讨论和学习,进入正题。
Hibernate目前用到的包:
antlr-2.7.6.jar、commons-collections-3.1.jar、dom4j-1.6.1.jar、hibernate3.jar、hibernate-jpa-2.0-api-1.0.0.Final.jar、javassist-3.12.0.GA.jar、jta-1.1.jar、slf4j-api-1.6.1.jar、slf4j-nop-1.6.1.jar
(1)hibernate.cfg.xml的配置:
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="dialect">org.hibernate.dialect.MySQLDialect</property>//SQL方言 <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost:3306/hibertest?useUnicode=true&characterEncoding=UTF-8</property> <property name="connection.username">root</property> <property name="connection.password">123</property> <property name="hbm2ddl.auto">update</property>//还有create,validate,create-drop等属性的设置 <property name="show_sql">true</property>//显示SQL语句到控制台 <!--配置持久化类--> <mapping class="com.xxx.entity.Parent" />//使用Annotation时的设置 <mapping resource="com/xxx/entity/Score.hbm.xml" />//使用Score.hbm.xml的设置 </session-factory> </hibernate-configuration>
Hibernate的基本应用:
配置Session:
private static Configuration configuration = new Configuration();//Configuration实例(用于加载配置) private static SessionFactory sessionFactory;//session工厂 private static ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();//当地线程,用户获取和设置session public static SessionFactory getSessionFactory() { sessionFactory = configuration.configure().buildSessionFactory(); //configuration.configure()默认加载classpath下(也就是src)下的hibernate.cfg.xml,我们可以为其指定路径configuration.configure("url"); return sessionFactory; } public static Session getSession() { Session session = (Session) threadLocal.get(); if (session == null || !session.isOpen()) {//判断session是否为空或者是否打开,如果不为空还创建,那么每次使用getSession()都创建一个新的session,自然对数据库的存取操作出现问题。其实还有很多种办法,但是核心还是我们每次对数据库操作的session的唯一性。这样说并不代表不关闭Session,关闭Session是线程安全的行为。只是说的是每次的操作! if (sessionFactory == null) { sessionFactory = getSessionFactory(); } session = sessionFactory.openSession(); } threadLocal.set(session);//设置session return session; } //注意:每次我们对数据库进行操作完后最好都要关闭Session。
事务封装例子:
public static boolean save(Object object) { boolean flag = false; Transaction tx = null; try { tx = getSession().beginTransaction();//打开事务 getSession().save(object); tx.commit();//提交事务 flag = true; } catch (Exception e) { e.printStackTrace(); tx.rollback();//回滚事务 } finally { if (getSession() != null) { getSession().close(); } } return flag; }
例子用所使用的持久化类:
//Student.class public class Student { private Integer uid; private String studentName; private Set<Score> score= new HashSet<Score>();//一个学生有多个成绩,所以需要用Set集合。 //private Score score;基于主键的双向一对一使用,不需要Set集合了。 //getter和setter方法略 } //Score.class public class Score { private Integer sid; private String scoreName; private Student student;//关联类Student使用的属性 //getter和setter方法略 }
(2)Score.hbm.xml的配置:(student.hbm.xml不列举,我只是大概描述配置,希望具体的用法还是让大家去实践,实践出真理!)
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.xxx.entity.Score" table="score" lazy="true"> <id name="sid" column="sid">//主键设置 <generator class="native" />//根据数据库选择生产策略,Mysql是自动增长 </id> <property name="scoreName" column="scoreName" type="java.lang.String" /> <many-to-one name="student" class="com.xxx.entity.Student" cascade="all" fetch="select" >//fetch="select",设置抓去策略select,Hibernate会发送一条select语句来抓去当前对象的关联实体和集合,实际应用中优化有限,不值得过多关注 <column name="kid" ></column> </many-to-one> </class> </hibernate-mapping>
(3)简要说明一下各xml里标签的应用:
<!--普通的配置--> <id name="sid" column="sid" type="java.lang.Integer">//主键设置,name为此实体类的id,column为表的对应字段 <generator class="native" />//根据数据库选择生产策略,Mysql是自动增长 //<generator class="assigned"/>主键是由人工分配的 </id> <property name="scoreName" column="scoreName" type="java.lang.String" />//name为实体类的属性,column同理,type为字段类型,整型为java.lang.Integer
<!--多对一配置-->在Score.hbm.xml中 <many-to-one name="student" class="com.xxx.entity.Student" cascade="all" fetch="select" > <column name="kid" ></column> </many-to-one> //fetch参数指定了关联对象抓取的方式是select查询还是join查询,select方式时先查询返回要查询的主体对象(列表),再根据关联外键id,每一个对象发一个select查询,获取关联的对象,形成n+1次查询;而join方式,主体对象和关联对象用一句外键关联的sql同时查询出来,不会形成多次查询。(默认是select),fetch="join",hibernate会通过select语句使用外连接来加载其关联实体或集合,此时lazy会失效。 //cascade有all(级联所有操作,等同于save-update和delete),save-update(级联保存更新等操作),delete(级联删除操作),none(不级联任何操作) //<column name="kid" ></column>指定外键名
<!--基于主键单向一对一-->让Score当成外表,是我们的选择把?呵呵 //在Score.hbm.xml中: <id name="sid" column="sid" type="java.lang.Integer"> <generator class="foreign"> <param name="property">student</param>//设置为foreign,把Score的主键关联至Student的主键,让Score的主键按照Student的主键生成。不能让其自动增长。 </generator> </id> <one-to-one name="student" constrained="true"/>//name设置的是关联类(在Score类中)constrained="true"表明该主键由关联类生成 // one-to-one 有个property-ref属性,是对应你要指定到那个字段的引用,不设置时,默认为引用表的主键。
<!--基于主键的双向一对一--> //根据单向一对一,只需要对student.hbm.xml补充设置Student关联Score就好了 <one-to-one name="score" cascade="all">
<!--基于外键的单向一对一-->//只在score.hbm.xml中设置 <many-to-one cascade="all" name="student" column="sid" not-null="true" unique="true" class="com.xxx.entity.Student"/> //unique="true" 表示多的一端也唯一
<!--双向一对多关联--> //在Student.hbm.xml中: <set name="scores" cascade="save-update" inverse="true"> <key><column name="tid" not-null="true"></key>//tid为外键 <one-to-many class="com.xxx.entity.Score"/> </set> //inverse="true"是让Student为主控方,由受控方Score维护,让一端维护的话,那么每次在删除等操作的时候,都会让一端去更新其关联的每一个多端,如果让多端维护,那么就不会有更新操作,数据库效率更高些。 //在Score.hbm.xml中: <many-to-one fetch="select" cascade="save-update" name="student" class="com.xxx.entity.Student"> <column name="tid" not-null="true"/> </many-to-one>
(4)Annotation配置Hibernate:
//这里就以实际的配置大概讲述一下,也许不是很完善,但是具体的用法还是需要我们去实践,再说一次,实践出真理!当用Annotation配置的时候,我们不需要xxx.hbm.xml这个文件了,所以hibernate.cfg.xml的映射也需要相关的改变,请参照hibernate。cgf.xml的配置 //Student.class中的配置: @Entity//声明为持久化类 public class Student { private Integer uid; private String studentName; private Set<Score> set = new HashSet<Score>(); public void setSet(Set<Score> set) { this.set = set; } @OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY,mappedBy="student")//一对多的配置,注意要使用mappedBy="Score类里的Student变量名",如果不使用mappedBy,那么会生成一个中间表来存储双方的关联关系,这样岂不是复杂了?mappedBy只在一对多、多对多、一对一里才有。多对一没有。cascade属性也就是级联关系,PERSIST(级联保存) REMOVE(级联删除) REFRESH(级联刷新) MERGE(级联更新) ALL(级联所有) public Set<Score> getSet() { return set; } @Id//主键 @GeneratedValue(strategy = GenerationType.AUTO)//主键生成策略(自增) public Integer getUid() { return uid; } public void setUid(Integer uid) { this.uid = uid; } public String getStudentName() { return studentName; } public void setStudentName(String studentName) { this.studentName = studentName; } } //Score.class中的配置: @Entity public class Score { private Integer sid; private String scoreName; private Student student; @Id//主键 @GeneratedValue//主键生成策略(默认也是自增) public Integer getSid() { return sid; } public void setSid(Integer sid) { this.sid = sid; } public String getScoreName() { return scoreName; } public void setScoreName(String scoreName) { this.scoreName = scoreName; } public void setStudent(Student student) { this.student = student; } @ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY) @JoinColumn(name="tid")//设置多的一方的表中的外键 public Student getStudent() { return student; }
对于基于主键的双向一对一的Annotation配置,弄不出来,希望懂的可以留言。
好了,暂且我先介绍到这里,以后会慢慢完善Hibernate的配置,注意设置延迟加载的利弊,当Lazy="true",如果关闭了Session再进行获取就会出错。当然,可以通过一些配置来解决这个问题,去网上搜索一下把。网上的资源我们得充分利用!
总结:(1)主要开发过程hibernate.cfg.xml+xxx.hbm.xml+实体类
(2)如果用Annotation配置实体类,那么xxx.hbm.xml可省略。开发模型为hibernate.cfg.xml+实体类
(3)当hibernate.hbm2ddl.auto=update不起作用时候在spring的session的sessionfactory加上: <property name="schemaUpdate">
<value>true</value>
</property>