(二)配置及用法之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的配置:
<!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 />//使用Annotation时的设置 <mapping resource="com/xxx/entity/Score.hbm.xml" />//使用Score.hbm.xml的设置</session-factory></hibernate-configuration>
private static Configuration configuration = new Configuration();//Configuration实例(用于加载配置)private static SessionFactory sessionFactory;//session工厂private static ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();//当地线程,用户获取和设置sessionpublic 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);//设置sessionreturn 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.classpublic class Student {private Integer uid;private String studentName;private Set<Score> score= new HashSet<Score>();//一个学生有多个成绩,所以需要用Set集合。 //private Score score;基于主键的双向一对一使用,不需要Set集合了。//getter和setter方法略}//Score.classpublic class Score {private Integer sid;private String scoreName;private Student student;//关联类Student使用的属性//getter和setter方法略}
<?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 />//根据数据库选择生产策略,Mysql是自动增长</id> <property name="scoreName" column="scoreName" type="java.lang.String" /><many-to-one name="student" cascade="all" fetch="select" >//fetch="select",设置抓去策略select,Hibernate会发送一条select语句来抓去当前对象的关联实体和集合,实际应用中优化有限,不值得过多关注<column name="kid" ></column></many-to-one> </class></hibernate-mapping>
<!--普通的配置--> <id name="sid" column="sid" type="java.lang.Integer">//主键设置,name为此实体类的id,column为表的对应字段 <generator />//根据数据库选择生产策略,Mysql是自动增长 //<generator column="scoreName" type="java.lang.String" />//name为实体类的属性,column同理,type为字段类型,整型为java.lang.Integer
<!--多对一配置-->在Score.hbm.xml中 <many-to-one name="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 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" 表示多的一端也唯一
<!--双向一对多关联-->//在Student.hbm.xml中:<set name="scores" cascade="save-update" inverse="true"> <key><column name="tid" not-null="true"></key>//tid为外键 <one-to-many cascade="save-update" name="student" not-null="true"/></many-to-one>
//这里就以实际的配置大概讲述一下,也许不是很完善,但是具体的用法还是需要我们去实践,再说一次,实践出真理!当用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中的配置:@Entitypublic 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;}