zoukankan      html  css  js  c++  java
  • Hibernate一 入门

    一 简介
    1.什么是ORM
    Object/Relation Mapping,即对象/关系映射。可以将其理解为一种规范,具体的ORM框架可以作为应用程序和数据库的桥梁。面向对象程序设计语言与关系数据库发展不同步时,需要一种中间解决方案,而ORM就是这样的解决方案 。ORM工具的唯一作用就是:把对持久化对象的保存、删除、修改等操作,转换成对数据库的操作。
    ORM并不是一种具体的产品,而是一类框架的总称,它概述了这类框架的基本特征:完成面向对象的程序设计语言到关系数据库的映射。
    基于ORM框架完成映射后,既可以利用面向对象程序设计语言的简单易用性,又可以利用关系数据库的技术优势。
    目前ORM的产品非常多,如Apache组织的QIB,Oracle的TopLink,JDO,JPA等等。
    2.Hibernate
    Hibernate是目前最流行的ORM框架之一,它是一个面向Java环境的对象/关系数据库映射工具
    它也是一个轻量级的O/R Mapping框架,是目前最流行的持久层解决方案,较之另一个持久层框架MyBATIS,更具有面向对象的特征
    Hibernate是ORM规范的实现框架,所有的ORM框架的作用:负责把面向对象的持久化操作,转化为数据库标准SQL语句去执行
    但是Hibernate不一定能提高程序的性能,可扩展性和可维护性
    ORM规范映射思想:一个表映射成一个类;一行记录(一条数据)映射成一个对象,一列(一个字段)映射成对象的属性
    3.下载:www.hibernate.org/downloads
    解压后的文档结构如下:
    documentation:各种相关的文档,包括Hibernate的参考文档和API文档等等
    lib:存放了核心类库以及编译和运行所依赖的第三方类库。其中lib路径下的required子目录下保存了运行Hibernate的核心类库,以及必需的第三方类库
    project:存放了Hibernate各种相关项目的源代码
    lgpl.txt、logo等杂项文件
    二 具体实现
    1.PO(持久化对象)
    Person.class
    public class Person {
    @Override
    public String toString() {
    return "Person [id=" + id + ", name=" + name + ", password=" + password
    + ", birthday=" + birthday + "]";
    }
    public Integer getId() {
    return id;
    }
    public void setId(Integer id) {
    this.id = id;
    }
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public int getPassword() {
    return password;
    }
    public void setPassword(int password) {
    this.password = password;
    }
    public Date getBirthday() {
    return birthday;
    }
    public void setBirthday(Date birthday) {
    this.birthday = birthday;
    }
    private Integer id;
    private String name;
    private int password;
    private Date birthday;
    public Person() {
    super();
    }
    public Person(String name, int password, Date birthday) {
    super();
    this.name = name;
    this.password = password;
    this.birthday = birthday;
    }
    }
    如上所示,Hibernate采用了POJO(普通的、传统的Java对象)作为持久化类,这就是Hibernate被称为低侵入式设计的原因。Hibernate不要求持久化类继承任何父类,或者实现任何接口,这样可以保证代码不被污染。
    注意:持久化设计时持久化类通常建议使用一个持久化标识符(ID),并且建议使用封装类(基本类型有默认值)。通常要给定一个无参构造器,因为有些操作是反射进行的,属性通常要提供getter/setter方法,持久化类不能是final类型。持久化类中如果使用了集合类型数据,只能使用接口类型进行声明(List,Set,Map),如:List list=new ArrayList();
    如何将一个POJO转换为PO呢?也就是说如何将上面的Person类进行持久化呢?Hibernate提供了三种方式:
    (1)使用持久化注解(以JPA标准注解为主)
    (2)使用JPA提供的xml配置文件,很少使用
    (3)使用Hibernate传统的xml映射文件(*.hbm.xml文件的形式)
    这里使用第一种和第三种方法作为示例
    a.建立Person.hbm.xml
    该文件是一个持久化映射文件,将Java对象映射到数据库表。几乎所有的ORM工具都需要一个数据库字段与JavaBean属性匹配的映射文件,在hibernate中一般命名为*.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 >
    //name指定需要持久化的类(包加类名),table指定需要映射的表名
    <class name="HibernateTest.Person" table="t_person"> <!-- 类对应到数据库中的表 -->
    <id name="id"> <!-- Person类中的id为class的id,id必须指定,name指定持久化类的持久化标识符名称,generate指定id生成策略-->
    <generator class="native"></generator> <!-- 该id为本地产生 -->
    </id>
    <property name="name" column="t_name"></property>
    <property name="password" length="6"></property>
    <property name="birthday"></property>
    </class>
    </hibernate-mapping>
    注意:在xml文件中,name对应的是java类中的对象,property为其他属性映射配置,name为持久化类中需要映射的属性名,column指定表的列名(不写表示默认使用属性名),length指定列存储数据长度,type指定字段类型
    b.使用持久化注解
    将Person.java修改为:
    @Entity
    @Table(name="t_person")
    public class Person {
    @Override
    public String toString() {
    return "Person [id=" + id + ", name=" + name + ", password=" + password
    + ", birthday=" + birthday + "]";
    }
    public Integer getId() {
    return id;
    }
    public void setId(Integer id) {
    this.id = id;
    }
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public int getPassword() {
    return password;
    }
    public void setPassword(int password) {
    this.password = password;
    }
    public Date getBirthday() {
    return birthday;
    }
    public void setBirthday(Date birthday) {
    this.birthday = birthday;
    }
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
    @Column(name="t_name")
    private String name;
    @Column(length=6)
    private int password;
    private Date birthday;
    public Person() {
    super();
    }
    public Person(String name, int password, Date birthday) {
    super();
    this.name = name;
    this.password = password;
    this.birthday = birthday;
    }
    }
    其中,@Entity注解声明该类是一个持久化类,@Table指定该类映射的表,@Id指定该类的标识属性,@GeneratedValue指定主键生成策略,@Column用于指定数据库中对应列的详细信息。由此可见,PO=POJO+持久化注解
    2.Hibernate配置文件
    在生成PO文件后,就要在hibernate.cfg.xml中配置各种信息。
    hibernate的project->etc中有各种模板,将其中的hibernate.cfg.xml复制到项目的src路径中。在这里展示一下mySQL数据库的连接方式:
    <hibernate-configuration>
    <session-factory>
    //配置成数据库方言模式,更方便数据库识别
    <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql:///mydb</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">123456</property>
    //数据库连接池
    <property name="hibernate.c3p0.max_size">20</property>
    <property name="hibernate.c3p0.min_size">1</property>
    <property name="hibernate.c3p0.timeout">5000</property>
    //根据需要自动创建数据库表
    <property name="hibernate.hbm2ddl.auto">update</property>
    <property name="show_sql">true</property>
    <property name="hibernate.format_sql">true</property>
    //这个是Person.hbm.xml对应的配置
    <mapping resource="HibernateTestPerson.hbm.xml"></mapping>
    //这个对应的是持久化注解的PO类的路径
    <mapping class="HibernateTest.Person"></mapping>
    </session-factory>
    </hibernate-configuration>
    注意:各种数据库的连接方式可以具体在hibernate.properties.template文件查找,该文件都有详细的定义。其中,mapping根据PO持久化的方式有两种选择。
    hibernate通过C3P0数据源来管理数据库连接,当程序创建数据源实例时,系统会一次性创建多个数据库连接,并将这些数据库连接保存在连接池中。程序访问数据库时,直接从连接池中取出一个空闲的数据库连接;访问结束后,无需关闭数据库直接将连接还给连接池即可。通过这种方式,可以避免频繁的获取数据库连接、关闭数据库连接所导致的性能下降。将optional路径下的C3P0的JAR包导入项目路径下。
    其中,<property name="hibernate.hbm2ddl.auto">update</property>,update表示程序启动时没有就创建表,有就检查有没有更新(推荐使用)
    3.编写测试程序test.java
    public class test {
    public static void main(String[] args) {
    //创建Configuration实例,并加载配置文件(hibernate.cfg.xml),唯一的作用是创建SessionFactory,一旦创建完成就被丢弃
    Configuration config=new Configuration().configure();
    SessionFactory factory=config.buildSessionFactory();
    Session session=factory.openSession();
    Transaction tx=session.beginTransaction();
    Person p=new Person(123,"admin",123456,new java.util.Date());
    //将Person对象持久化到数据库
    session.save(p);
    //事务提交
    tx.commit();
    session.close();
    //关闭SessionFactory,通常不用手动关闭
    factory.close();
    }
    }
    结果:
    Hibernate:
    create table t_person (
    id integer not null auto_increment,
    t_name varchar(255),
    password integer,
    birthday datetime,
    primary key (id)
    ) ENGINE=InnoDB
    Hibernate:
    insert
    into
    t_person
    (t_name, password, birthday)
    values
    (?, ?, ?)
    同时数据库中建立了一个表为t_person,字段分别为id(1),t_name(admin),password(123456),birthday(...)
    三 Hibernate的体系结构
    1.SessionFactory
    这是Hibernate的关键对象,它是单个数据库映射关系经过编译后的内存镜像,是线程安全的。应用程序从SessionFactory中获得Session实例,它在多个线程间进行共享。通常情况下,整个应用只有唯一的一个会话工厂。但是如果访问多个数据库,就需要对每一个数据库使用一个会话工厂。会话工厂缓存了生成的SQL语句和hibernate在运行时使用的映射元数据。
    2.Session
    它是应用程序与持久存储层之间交互操作的一个单线程对象,所有的PO必须在Session管理下才可以进行持久化操作。
    生存期很短,底层封装了JDBC连接,也是Transaction的工厂。
    Session有一个必选的一级缓存,显式执行flush之前,所有持久化操作都在缓存中。
    3.Transaction
    代表一次原子操作,具有数据库事务的概念。将应用代码从底层的事务实现中抽象出来,这可能是一个JDBC事务,一个JTA用户事务或是一个公共对象请求代理结构(CORBA),允许应用通过一组一致的API控制事务边界。这有助于保持Hibernate应用在不同类型的执行环境或容器中的可移植性。使用Hibernate进行操作(增删改)必须显示的调用它,即必须要commit。
    整个的逻辑结构为:
    业务逻辑层:业务对象(对象、属性、关联、继承)-->Person.java
    持久化层: ORM API/ORM 实现-->Person.hbm.xml
    JDBC-->hibernate.cfg.xml
    数据库层:关系型数据库
    四 改变持久化对象状态的方法
    1.持久化实体
    包括save()和persist()两种方法,如:
    Person p=new Person();
    p.setName("lyy");
    session.save(p);
    save()与persist()方法的区别:使用save()方法时会返回该持久化对象的标识属性值,即主键值;使用persist()方法时,不会返回任何值。程序执行save()方法会立即将持久化对应的数据插入到数据库,而persist()方法则保证当它在一个事务外部被调用时,并不立即转换成insert语句,在需要封装一个长会话时,这个方法尤为重要。
    2.根据主键加载持久化类
    主要包括load()和get()方法,如:
    Person p=session.load(Person.class,1);
    load()和get()的区别:主要区别在于是否延迟加载。load()方法具有延迟加载功能,Load()不会立即访问数据库,当试图加载的记录不存在时,可能返回一个未初始化的代理对象;而get()方法总是立即访问数据库,当记录不存在时,直接返回null
    3.更新持久化实体
    Person p=session.load(Person.class,1);
    p.setPassword("345345");
    也就是说,使用load()方法后就可以直接对实体进行更新。
    4.使用saveOrUpdate()
    saveOrUpdate()表示新增或更新,若id存在就是更新,不存在就报更新失败;如果不给id,就是新增
    public class test {
    private static void testSaveOrUpdate(){
    Configuration config=new Configuration().configure();
    SessionFactory factory=config.buildSessionFactory();
    Session session=factory.openSession();
    Transaction tx=session.beginTransaction();
    Person p=new Person();
    p.setId(3);
    p.setPassword(12344);
    session.saveOrUpdate(p);
    tx.commit();
    session.close();
    }
    public static void main(String[] args) {
    testSaveOrUpdate();
    }
    }
    修改成功后,密码为12344,其他为空
    5.使用merge()
    public class test {
    private static void merge(){
    Configuration config=new Configuration().configure();
    SessionFactory factory=config.buildSessionFactory();
    Session session=factory.openSession();
    Transaction tx=session.beginTransaction();
    Person p=(Person)session.get(Person.class, 3);
    p.setName("lyy");
    Person p2=(Person)session.merge(p);
    p2.setBirthday(new java.util.Date());
    tx.commit();
    session.close();
    }
    public static void main(String[] args) {
    merge();
    }
    }
    注:持久化状态对象会在session关闭的时候如果内存数据和表数据不一致,将自动同步到数据库表
    或者:
    private static void testSaveOrUpdate(){
    Configuration config=new Configuration().configure();
    SessionFactory factory=config.buildSessionFactory();
    Session session=factory.openSession();
    Transaction tx=session.beginTransaction();
    Person p=new Person();
    p.setId(3);
    p.setName("kui");
    session.merge(p);
    tx.commit();
    session.close();
    }
    结果:name为kui,其他为空,相当于update
    6.删除有两种方法:
    删除持久化状态对象:
    public class test {
    public static void main(String[] args) {
    Configuration config=new Configuration().configure();
    SessionFactory factory=config.buildSessionFactory();
    Session session=factory.openSession();
    Transaction tx=session.beginTransaction();
    Person p=(Person)session.load(Person.class,3);
    session.delete(p);
    tx.commit();
    session.close();
    }
    }
    删除临时化状态对象:
    public static void main(String[] args) {
    Configuration config=new Configuration().configure();
    SessionFactory factory=config.buildSessionFactory();
    Session session=factory.openSession();
    Transaction tx=session.beginTransaction();
    Person p=new Person();
    p.setId(4);
    session.delete(p);
    tx.commit();
    session.close();
    }
    使用junit进行测试:
    在项目中new->Junit Test Case->选中setUp()和tearDown()方法,即初始化和最后的资源释放
    public class myTest {
    SessionFactory factory=null;
    Session session=null;
    Transaction tx=null;
    @Before
    public void setUp() throws Exception {
    System.out.println("---初始化数据---");
    Configuration config=new Configuration().configure();
    factory=config.buildSessionFactory();
    session=factory.openSession();
    tx=session.beginTransaction();
    }
    @After
    public void tearDown() throws Exception {
    System.out.println("---释放资源---");
    if(session.isOpen()){
    session.close();
    }
    }
    @Test
    public void test() {
    Person p=new Person(2,"admin",123,new Date());
    session.persist(p);
    tx.commit();
    }
    }
    run as junit test->查看结果

  • 相关阅读:
    CSS 单行超出隐藏
    python开发学习day12 (函数参数;函数对象)
    作业day11
    python开发学习day11 (函数; 返回值 ; 形参与实参 )
    python开发学习day10 (文件指针; 文本修改)
    作业day09
    python开发学习day09 (with上下文处理; b模式; +模式; 文件操作)
    作业day08
    python开发学习day08 (集合; 文件操作)
    作业day07
  • 原文地址:https://www.cnblogs.com/lyy-2016/p/5702013.html
Copyright © 2011-2022 走看看