Hibernate学习之映射1

引言

Hibernate提供了三种方式将POJO类变成PO类:

  • 使用持久化注解(以JPA 标准注解为主,如果有一些特殊要求,则依然需要使用Hibernate 本身提供的注解)
  • 使用JPA2 提供的XML 配置描述文件( XML deployment descriptor ),这种方式可以让Hibernate的PO 类与IPA 实体类兼容。但在实际开发中,很少有公司使用这种方式。
  • 使用Hibernate 传统的XML映射文件 (* .hbm. xm l 文件的形式) ,由于这种方式是传统Hibernate的推荐方式,因此依然有少数企业会采用这种方式。
    因为第一种方式为主流,那么我们就学习一下!

持久化注解

@Entity
        被该注解修饰的POJO 就是一个实体。使用该注解时可指定一个name 属性, name 属性指定该实体类的名称,但大部分时候无须指定该属性,因为系统默认以该类的类名作为实体!

@Entity//注释声明该类为Hibernate持久化类

@Table

@Table(name="table1")//指定映射的表

在这里插入图片描述
在这里插入图片描述
@UniqueConstraint
        用于为数据表定义唯一约束。它的用法非常简单,使用该注解时可以指定如下唯一的属性。

  • columnName:该属性的值是一个字符串数组,每个字符串元素代表一个数据列。

@Index
        用于为数据表定义索引。
在这里插入图片描述
@Proxy
        该注解的proxyClass 属性指定一个接口,在延迟加载时作为代理使用,也可以在这里指定该类自己的名字。
@DynamicInsert
        指定用于插入记录的insert 语句是否在运行时动态生成,并且只插入那些非空宇段。该属性的值默认是false 。开启该属性将导致Hibernate 需要更多时间来生成SQL 语句。
DynamicUpdate
        指定用于更新记录的update 语句是否在运行时动态生成,并且只更新那些改变过的字段。该属性的值默认是false 。开启该属性将导致Hibernate 需要更多的时间来生成SQL语句。
在这里插入图片描述
@SelectBeforeUpdate
        指定Hibernate 在更新( update )某个持久化对象之前是否需要先进行一次查询( select ) 。如果将该注解的value 值设为true ,则Hibernate 可以保证只有当持久化对象的状态被修改过时,才会使用update i吾句来保存其状态(即使程序显式使用saveOrUpdate()来保存该对象,但如果Hibernate 查询到对应记录与该持久化对象的状态相同,也不会使用update语句来保存其状态) 。该注解的value 值默认为false 。
@PolymorphismType
        当采用TABLE_PER_CLASS 继承映射策略时,该注解用于指定是否需要采用隐式多态查询。该注解的value 的默认值为PolymorphismType.IMPLICIT ,即支持隐式多态查询。
@Where
        该注解的clause 属性可指定一个附加的SQL 语句过滤条件(类似于添加where 子句)如果一旦指定了该注解,则不管采用load()、get()还是其他查询方法,只要试图加载该持久化类的对象时,该where 条件就会生效。也就是说,只有符合该where 条件的记录才会被加载。
@BatchSize
        当H ibernate 抓取集合属性或延迟加载的实体时,该注解的size 属性指定每批抓取的实例数。
@OptimisticLocking
        该注解的type 属性指定乐观锁定策略。Hibernate 支持OptimisticLockType .ALL 、OptimisticLockType.DIRTY 、OptimisticLockType.NONE OptimisticLockType. VERSION 这4 个枚举值。默认值OptimisticLockType.VERSION。
@Check
        该注解可通过constraints 指定一个SQL 表达式,用于为应持久化类所对应的表指定一个Check 约束。
@Subselect
        该注解用于映射不可变的、只读实体。通俗地说,就是将数据库的子查询映射成Hibernate 持久化对象。当需要使用视图(其实质就是一个查询〉来代替数据表时,该注解比较有用。

映射属性

@Column
        为了指定某个属性所映射的数据列的详细信息,如列名,列名字段长度等,在实体类中使用 @Column 修饰该属性。
在这里插入图片描述
在这里插入图片描述
@Formula
        该注解的value 属性可指定一个SQL 表达式,指定该属性的值将根据表达式来计算。持久化类对应的表中没有和计算属性对应的数据列-------因为该属性值是动态计算出来的,无需保存到数据库。
在这里插入图片描述

import javax.persistence.*;


import javax.persistence.*;
import org.hibernate.annotations.Formula;

@Entity
@Table(name="news_inf")
public class News
{
    // 消息类的标识属性
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
    // 消息标题
    private String title;
    // 消息内容
    private String content;
    // 消息全部内容,由系统根据公式生成
    @Formula("(select concat(nt.title,nt.content)"
            + "from news_inf nt where nt.id= id)")
    private String fullContent;

    // id的setter和getter方法
    public void setId(Integer id)
    {
        this.id = id;
    }
    public Integer getId()
    {
        return this.id;
    }

    // title的setter和getter方法
    public void setTitle(String title)
    {
        this.title = title;
    }
    public String getTitle()
    {
        return this.title;
    }

    // content的setter和getter方法
    public void setContent(String content)
    {
        this.content = content;
    }
    public String getContent()
    {
        return this.content;
    }

    // fullContent的setter和getter方法
    public void setFullContent(String fullContent)
    {
        this.fullContent = fullContent;
    }
    public String getFullContent()
    {
        return this.fullContent;
    }
}

解释:
上面PO 类的创!Content 属性并不需要采用数据列保存, 该属性的值将由系统根据SQL 表达式来生成,所以程序映射fullContent 属性时使用了@Formula 修饰。
MySQL教程之concat以及group_concat的用法
在这里插入图片描述
@Generated
        设置该属性映射的数据列的值是否由数据库生成, 该注解的value 属性可以接受GenerationTime.NEVER (不由数据库生成) 、GenerationTime.INSERT (该属性值在执行insert语句时生成, 但不会在执行update 语句时重新生成) 和Generati onTime .ALWA YS (该属性值在执行insert 和update 语句时都会被重新生成)这三个值的其中之一。

import javax.persistence.*;


import javax.persistence.*;
import org.hibernate.annotations.Formula;
import org.hibernate.annotations.Generated;
import org.hibernate.annotations.GenerationTime;

@Entity
@Table(name="news_inf")
public class News
{
    // 消息类的标识属性
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
    // 消息标题
    private String title;
    // 消息内容
    private String content;
    // 指定@Generated的value为ALWAYS,表明该属性的值由数据库生成,
    // Hibernate会在每次执行insert、update时执行select语句来查询获取该属性的值
    @Generated(GenerationTime.ALWAYS)
    private String fullContent;

    // id的setter和getter方法
    public void setId(Integer id)
    {
        this.id = id;
    }
    public Integer getId()
    {
        return this.id;
    }

    // title的setter和getter方法
    public void setTitle(String title)
    {
        this.title = title;
    }
    public String getTitle()
    {
        return this.title;
    }

    // content的setter和getter方法
    public void setContent(String content)
    {
        this.content = content;
    }
    public String getContent()
    {
        return this.content;
    }

    // fullContent的setter和getter方法
    public void setFullContent(String fullContent)
    {
        this.fullContent = fullContent;
    }
    public String getFullContent()
    {
        return this.fullContent;
    }
}
import javafx.fxml.FXMLLoader;
import org.hibernate.*;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.query.Query;
import org.hibernate.cfg.Configuration;

import javax.imageio.spi.ServiceRegistry;
import javax.persistence.metamodel.EntityType;

import java.util.Map;

public class Main {
    public static void main(final String[] args) throws Exception {
        // 实例化Configuration,
        Configuration conf = new Configuration().configure();

        SessionFactory sf = conf.buildSessionFactory();
        // 创建Session
        Session sess = sf.openSession();
        // 开始事务
        Transaction tx = sess.beginTransaction();
        // 创建消息对象
        News n = new News();
        // 设置消息标题和消息内容
        n.setTitle("疯狂Java联盟成立了");
        n.setContent("疯狂Java联盟成立了,"
                + "网站地址http://www.crazyit.org");
        // 保存消息
        sess.save(n);
//		News n = (News)sess.get(News.class , 1);
//		// 输出fullContent值
//		System.out.println(n.getFullContent());
        // 提交事务
        tx.commit();
        // 关闭Session
        sess.close();
        sf.close();

    }
}

在这里插入图片描述

使用@Transient修饰不想持久保存属性

        在默认情况下,持久化类的所有属性会自动映射到数据表的数据列。如果在实际应用中不想持久保存某些属性,则可以考虑使用@Transient 来修饰它们。

import javax.persistence.*;

@Entity
@Table(name="news_inf")
public class News
{
    // 消息类的标识属性
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Integer id;
    // 消息标题
    // @Column指定该属性映射的列信息,此处指定了列名、长度
    @Column(name="news_title" , length=50)
    private String title;
    // 消息内容
    @Transient
    private String content;

    // id的setter和getter方法
    public void setId(Integer id)
    {
        this.id = id;
    }
    public Integer getId()
    {
        return this.id;
    }

    // title的setter和getter方法
    public void setTitle(String title)
    {
        this.title = title;
    }
    public String getTitle()
    {
        return this.title;
    }

    // content的setter和getter方法
    public void setContent(String content)
    {
        this.content = content;
    }
    public String getContent()
    {
        return this.content;
    }
}
import org.hibernate.*;
import org.hibernate.query.Query;
import org.hibernate.cfg.Configuration;

import javax.persistence.metamodel.EntityType;

import java.util.Map;

public class Main {
    private static final SessionFactory ourSessionFactory;

    static {
        try {
            Configuration configuration = new Configuration();
            configuration.configure();
            ourSessionFactory = configuration.buildSessionFactory();
        } catch (Throwable ex) {
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static Session getSession() throws HibernateException {
        return ourSessionFactory.openSession();
    }

    public static void main(final String[] args) throws Exception {
        final Session session = getSession();
        try {
            // 开始事务
            Transaction tx = session.beginTransaction();
            // 创建消息对象
            News n = new News();
            // 设置消息标题和消息内容
            n.setTitle("疯狂Java联盟成立了");
            n.setContent("疯狂Java联盟成立了,"
                    + "网站地址http://www.crazyit.org");
            // 保存消息
            session.save(n);
            // 提交事务
            tx.commit();
        } finally {
            session.close();
        }
    }
}

在这里插入图片描述
使用@ Tra nsient 修饰了content ,这意味着Hiberna t e 将该持久化类映射到底层数据表时,content 不会映射到任何数据列; 当保存一个N ews 实体时,在N ews 实体中content 值不会被保存到数据中。

使用@Enumerated修饰枚举类型的属性

        在有些极端的情况下, 持久化类的属性不是普通的Java 类型,而是一个枚举类型,这意味着该属性只能接受有限的几个固定值。在这种情况下,可以考虑使用@E num erated 修饰实体类中枚举类型的属性。例如, 如下程序定义了一个Seaso n 枚举类。

package Season;

public enum Season
{
    春季,夏季,秋季,冬季
}

        对于枚举值而言,既可在程序中通过枚举值的名字来代表,也可使用枚举值的序号来代表。假如想在程序中使用Season 枚举值表示春季, 则既可用“春季”枚举值的名称代表,也可用枚举值的序号。代表同样地底层数据库既可保存枚举值名称来代表枚举值,也可保存枚举值序号来代表枚举值,这一点可通过@Enumerated 的value 属性来指定.当@ Enumerated 的value 属性为EnumType.STRING时,底层数据库保存枚举值的名称;当@ Enumerated 的value属性为EnumType.ORDINAL 时,底层数据库保存枚举值的序号。

import Season.Season;
import org.hibernate.*;
import org.hibernate.query.Query;
import org.hibernate.cfg.Configuration;

import javax.persistence.metamodel.EntityType;

import java.util.Map;

public class Main {
    private static final SessionFactory ourSessionFactory;

    static {
        try {
            Configuration configuration = new Configuration();
            configuration.configure();
            ourSessionFactory = configuration.buildSessionFactory();
        } catch (Throwable ex) {
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static Session getSession() throws HibernateException {
        return ourSessionFactory.openSession();
    }

    public static void main(final String[] args) throws Exception {
        final Session session = getSession();
        try {
            // 开始事务
            Transaction tx = session.beginTransaction();
            // 创建消息对象
            News n = new News();
            // 设置消息标题和消息内容
            n.setTitle("疯狂Java联盟成立了");
            n.setContent("疯狂Java联盟成立了,"
                    + "网站地址http://www.crazyit.org");
            // 保存消息
            n.setHappenSeason(Season.夏季);
            session.save(n);
            // 提交事务
            tx.commit();
        } finally {
            session.close();
        }
    }
}

在这里插入图片描述

使用@LOb,@Basic修饰大数据类型的属性

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!--加载数据库驱动-->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/hibernate?serverTimezone=UTC</property>
        <property name="connection.username">root</property>
        <property name="connection.password">123</property>
        <!--指定数据库方言-->
        <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
        <!-- DB schema will be updated if needed -->
        <property name="hibernate.hbm2ddl.auto">update</property>
        <!--在控制台显示SQL语句-->
        <property name="show_sql">true</property>
        <!--将SQL脚本中语句格式化在输出-->
        <property name="hibernate.format_sql">true</property>
        <!--罗列所有的持久化类-->
        <mapping class="Person"/>
    </session-factory>
</hibernate-configuration>
import javax.persistence.*;

@Entity
@Table(name="person_inf")
public class Person
{
    @Id // 用于修饰标识属性
    // 指定该主键列的主键生成策略
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Integer id;
    // @Column指定该属性映射的列信息,此处指定了列名、长度
    @Column(name="person_name" , length=50)
    private String name;
    @Lob
    @Basic(fetch=FetchType.LAZY)
    @Column(nullable=true)
    private byte[] pic;

    // id的setter和getter方法
    public void setId(Integer id)
    {
        this.id = id;
    }
    public Integer getId()
    {
        return this.id;
    }

    // name的setter和getter方法
    public void setName(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return this.name;
    }

    // pic的setter和getter方法
    public void setPic(byte[] pic)
    {
        this.pic = pic;
    }
    public byte[] getPic()
    {
        return this.pic;
    }
}
import org.hibernate.*;
import org.hibernate.query.Query;
import org.hibernate.cfg.Configuration;

import javax.persistence.metamodel.EntityType;

import java.io.File;
import java.io.FileInputStream;
import java.util.Map;

public class Main {
    private static final SessionFactory ourSessionFactory;

    static {
        try {
            Configuration configuration = new Configuration();
            configuration.configure();

            ourSessionFactory = configuration.buildSessionFactory();
        } catch (Throwable ex) {
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static Session getSession() throws HibernateException {
        return ourSessionFactory.openSession();
    }

    public static void main(final String[] args) throws Exception {
        final Session session = getSession();
        try {
            Transaction tx = session.beginTransaction();
            // 创建Person对象
            Person person = new Person();
            // 为Person对象的属性设置值
            person.setName("crazyit.org");
            File file = new File("logo.jpg");
            byte[] content = new byte[(int)file.length()];
            new FileInputStream(file).read(content);
            person.setPic(content);
            // 保存Person对象
            session.save(person);
        } finally {
            session.close();
        }
    }
}

在这里插入图片描述
Person 实体设置b yte []类型的属性值,程序使用IO 流读取了磁盘上的一张图片文件,并将图片文件的数据放入b yte [ ]数组中,然后将该byte [ ]数组的值作为setPic()方法的参数传入,这样就为Pe r son 实体的pi e 属性设置成功。
为了提高效率
有一种可能的情况是,程序只是需要访问该P ers on 对象的name 属性,根本不关心Person 对象的pie 属性,那么Hibernate 就白白浪费时间来加载pie 属性了,这显然不是一种好的做法。
为了改变这种情况, 程序希望有一种机制可以做到: Hibernate 加载Person 对象时并不立即加载它
的pie 属性,而是只加载一个“虚拟”的代理,等到程序真正需要pie 属性时才从底层数据表中加载数
据一一这就是典型的代理模式。Hi b ernate 为这种机制提供了支持,并将这种机制称为延迟加载,只要在开发实体时使用@Basic 修饰该属性即可。
在这里插入图片描述

使用@Temporal修饰日期类型的属性

import org.hibernate.*;
import org.hibernate.query.Query;
import org.hibernate.cfg.Configuration;

import javax.persistence.metamodel.EntityType;

import java.util.Map;

public class Main {
    private static final SessionFactory ourSessionFactory;

    static {
        try {
            Configuration configuration = new Configuration();
            configuration.configure();

            ourSessionFactory = configuration.buildSessionFactory();
        } catch (Throwable ex) {
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static Session getSession() throws HibernateException {
        return ourSessionFactory.openSession();
    }

    public static void main(final String[] args) throws Exception {
        final Session session = getSession();
        try {
            Transaction tx = session.beginTransaction();
            // 创建Person对象
            Person person = new Person();
            // 为Person对象的属性设置值
            person.setName("crazyit.org");
            person.setBirth(new java.util.Date());
            // 保存Person对象
            session.save(person);

        } finally {
            session.close();
        }
    }
}
import javax.persistence.*;
import java.util.Date;

@Entity
@Table(name="person_inf")
public class Person
{
    @Id // 用于修饰标识属性
    // 指定该主键列的主键生成策略
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Integer id;
    // @Column指定该属性映射的列信息,此处指定了列名、长度
    @Column(name="person_name" , length=50)
    private String name;
    @Temporal(TemporalType.DATE)
    private Date birth;

    // id的setter和getter方法
    public void setId(Integer id)
    {
        this.id = id;
    }
    public Integer getId()
    {
        return this.id;
    }

    // name的setter和getter方法
    public void setName(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return this.name;
    }

    // birth的setter和getter方法
    public void setBirth(Date birth)
    {
        this.birth = birth;
    }
    public Date getBirth()
    {
        return this.birth;
    }

}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值