Hibernate(二)

1 缓存

1.1 什么是缓存?

  • 数据存到数据库里面,数据库本身是文件系统,使用流操作文件效率不是很高。将数据存在内存里面不需要使用流的方式,可以直接读取内存中的数据。把数据收到内存中可以提高读取效率。
  • 提供缓存的目的是为了让数据访问的速度适应CPU的处理速度

1.2 Hibernate的一级缓存

  • hibernate的一级缓存是默认打开的。
  • hibernate的一级缓存的使用范围是session的范围,即从session被实例化到被关闭的过程
  • hibernate的一级缓存中,存储的数据必须是持久态(由session获得的)的数据。
  • hibernate的二级缓存默认不是打开的,并且现在都用redis去代替它,其使用范围为sessionFactory范围

1.3 验证一级缓存的存在

  • 验证方式:两次查询uid = 1的对象,第一次会查数据库,第二次就会从缓存中取
        Students students = session.get(Students.class,3);
        Students students2 = session.get(Students.class,3);

只有第一句会向数据库发送sql语句。

1.4 一级缓存的执行过程

  • 调用Students students = session.get(Students.class,3);后
  • 首先查询一级缓存区,查看是否存在id = 3的这个对象,如果存在则直接返回。
  • 如果不存在,则向数据库发送请求,返回的对象再存入一级缓存中。

1.5 一级缓存特性-持久态自动更新数据库

  • 持久态数据会自动更新数据库而不需要去调用类似session.update()方法。
Students students = session.get(Students.class,3);
students.setName("jacob");
//session.update(students);//不需要调用update也会更新数据库
  • 原理如下图:


    特性执行过程

2 事务标准写法

    @Test
    public void testTX(){
        StandardServiceRegistry standardServiceRegistry = null;
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try {
            standardServiceRegistry = new StandardServiceRegistryBuilder().configure().build();
            sessionFactory = new MetadataSources(standardServiceRegistry).buildMetadata().buildSessionFactory();
            session = sessionFactory.openSession();
            //开启事务
            tx = session.beginTransaction();
            Students students = session.get(Students.class,3);
            students.setGender("女");
            //抛出异常,回滚,性别仍是男
            int a = 1/0;
            System.out.println(a);
            students.setGender("男");
            tx.commit();
        }catch (Exception e){
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

3 三种查询api

  • Query对象
            Query query = session.createQuery("from Students");
            List<Students> list = query.list();
            for(Students student:list){
                System.out.println(student);
            }
  • Criteria对象
            Criteria criteria = session.createCriteria(Students.class);
            List<Students> list = criteria.list();
            for(Students student:list){
                System.out.println(student);
            }
  • SQLQuery对象
//返回数组类型
            SQLQuery sqlQuery  = session.createSQLQuery("select * from students");
            List<Object[]> list = sqlQuery.list();
            for(Object[] objects:list){
                System.out.println(Arrays.toString(objects));
            }
//返回对象类型
            SQLQuery sqlQuery  = session.createSQLQuery("select * from students");
            sqlQuery.addEntity(Students.class);
            List<Students> list = sqlQuery.list();
            for(Students students:list){
                System.out.println(students);
            }

4 一对多操作

4.1 一对多配置

  • 以联系人与客户为例,客户是一,联系人是多。
  1. 创建两个实体类,客户和联系人。
  2. 让两个实体类互相表示。
  3. 创建映射文件,配置一对多关系。(映射文件中,表示所有联系人)
  4. 配置多对一关系。(映射文件中,表示所属客户)。
  5. 将映射文件引入核心配置文件。
  • 接来下是各个步骤对应的代码:
    1/2. 实体类创建并互相表示
import java.util.List;

public class Customer {
    private Integer cid;
    private String custName;
    private String custLevel;
    private String custSource;
    private String custPhone;
    private String custMobile;
    private List<Contacter> list;

    public List<Contacter> getList() {
        return list;
    }

    public void setList(List<Contacter> list) {
        this.list = list;
    }

    public Customer() {
    }

    public Customer(Integer cid, String custName, String custLevel, String custSource, String custPhone, String custMobile, List<Contacter> list) {
        this.cid = cid;
        this.custName = custName;
        this.custLevel = custLevel;
        this.custSource = custSource;
        this.custPhone = custPhone;
        this.custMobile = custMobile;
        this.list = list;
    }

    public Integer getCid() {
        return cid;
    }

    public void setCid(Integer cid) {
        this.cid = cid;
    }

    public String getCustName() {
        return custName;
    }

    public void setCustName(String custName) {
        this.custName = custName;
    }

    public String getCustLevel() {
        return custLevel;
    }

    public void setCustLevel(String custLevel) {
        this.custLevel = custLevel;
    }

    public String getCustSource() {
        return custSource;
    }

    public void setCustSource(String custSource) {
        this.custSource = custSource;
    }

    public String getCustPhone() {
        return custPhone;
    }

    public void setCustPhone(String custPhone) {
        this.custPhone = custPhone;
    }

    public String getCustMobile() {
        return custMobile;
    }

    public void setCustMobile(String custMobile) {
        this.custMobile = custMobile;
    }
}
public class Contacter {
    private Integer conId;
    private String conName;
    private String conGender;
    private String conPhone;
    private Customer customer;

    public Contacter() {
    }

    public Contacter(Integer conId, String conName, String conGender, String conPhone, Customer customer) {
        this.conId = conId;
        this.conName = conName;
        this.conGender = conGender;
        this.conPhone = conPhone;
        this.customer = customer;
    }

    public Integer getConId() {
        return conId;
    }

    public void setConId(Integer conId) {
        this.conId = conId;
    }

    public String getConName() {
        return conName;
    }

    public void setConName(String conName) {
        this.conName = conName;
    }

    public String getConGender() {
        return conGender;
    }

    public void setConGender(String conGender) {
        this.conGender = conGender;
    }

    public String getConPhone() {
        return conPhone;
    }

    public void setConPhone(String conPhone) {
        this.conPhone = conPhone;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }
}
  1. 创建映射文件配置一对多关系
<?xml version='1.0' encoding='utf-8'?>
<!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="Customer" table="customer">
        <id name="cid" type="int">
            <column name="cid"/>
            <generator class="native"/>
        </id>
        <property name="custName" type="java.lang.String">
            <column name="custName"/>
        </property>
        <property name="custLevel" type="java.lang.String">
            <column name="custLevel"/>
        </property>
        <property name="custSource" type="java.lang.String">
            <column name="custSource"/>
        </property>
        <property name="custMobile" type="java.lang.String">
            <column name="custMobile"/>
        </property>
        <property name="custPhone" type="java.lang.String">
            <column name="custPhone"/>
        </property>
        <!--name为集合名称 -->
        <set name="list">
            <!--外键名称-->
            <key column="clid">
            </key>
            <one-to-many class="Contacter"/>
        </set>
    </class>
</hibernate-mapping>
  1. 创建多对一关系
<?xml version='1.0' encoding='utf-8'?>
<!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="Contacter" table="contacter">
        <id name="conId" type="int">
            <column name="conId"/>
            <generator class="native"/>
        </id>
        <property name="conName" type="java.lang.String">
            <column name="conName"/>
        </property>
        <property name="conGender" type="java.lang.String">
            <column name="conGender"/>
        </property>
        <property name="conPhone" type="java.lang.String">
            <column name="conPhone"/>
        </property>
        <many-to-one name="customer" class="Customer" column="clid"/>
    </class>
</hibernate-mapping>
  1. 导入配置文件
        <mapping resource="Contacter.hbm.xml"/>
        <mapping resource="Customer.hbm.xml"/>
  1. 编写工具类 + 测试
public class HibernateUtils {
    static StandardServiceRegistry ssregistry = null;
    static SessionFactory sessionFactory = null;
    static {
        ssregistry = new StandardServiceRegistryBuilder().configure().build();
        sessionFactory = new MetadataSources(ssregistry).buildMetadata().buildSessionFactory();
    }
    public static Session getSessionObject(){
        return sessionFactory.getCurrentSession();
    }
    public static SessionFactory getSessionFactory(){
        return sessionFactory;
    }
    public static void main(String []args){

    }
}

运行该类即可发现数据库创建了两张表。

结果

4.2 级联保存

  • 方式一:
public class HibernateOneToManyTest {
    @Test
    public void oneToManyTest(){
        Session session = null;
        SessionFactory sessionFactory = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtils.getSessionFactory();
            session = HibernateUtils.getSessionObject();
            tx = session.beginTransaction();
            Customer customer = new Customer();
            customer.setCustLevel("vip");
            customer.setCustMobile("111");
            customer.setCustName("阿里巴巴");
            customer.setCustSource("网络");
            customer.setCustPhone("222");

            Contacter contacter = new Contacter();
            contacter.setConGender("男");
            contacter.setConName("jacob");
            contacter.setConPhone("333");

            customer.getList().add(contacter);
            contacter.setCustomer(customer);
            session.save(customer);
            session.save(contacter);
            tx.commit();
        }catch (Exception e){
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }
}
  • 方式二:
  1. 首先在映射文件中添加配置cascade="save-update"
        <!--name为集合名称 -->
        <set name="list" cascade="save-update">
            <!--外键名称-->
            <key column="clid">
            </key>
            <one-to-many class="Contacter"/>
        </set>
  1. 代码:
            Customer customer = new Customer();
            customer.setCustLevel("vip");
            customer.setCustMobile("111");
            customer.setCustName("因特尔");
            customer.setCustSource("网络");
            customer.setCustPhone("222");

            Contacter contacter = new Contacter();
            contacter.setConGender("男");
            contacter.setConName("rose");
            contacter.setConPhone("333");

            customer.getList().add(contacter);
            session.save(customer);

4.3 级联删除

  • 有外键关联时的删除做法。
    直接删除一个customer是会报错的,因为有外键对其关联。


    删除报错
  • 做法步骤应如下:
  1. 删除从表的对应数据
  2. 删除主表对应数据
  • 级联删除的步骤如下:
  1. 在客户映射文件进行配置
        <!--name为集合名称 -->
        <set name="list" cascade="save-update,delete">
            <!--外键名称-->
            <key column="clid">
            </key>
            <one-to-many class="Contacter"/>
        </set>
            Customer customer = session.get(Customer.class,2);
            session.delete(customer);

4.4 更改联系人

            Customer customer = session.get(Customer.class,1);
            Contacter contacter = session.get(Contacter.class,11);
            customer.getList().add(contacter);
            contacter.setCustomer(customer);
  • 问题在于会进行两次外键设置,使得运行负担较大。
  • 解决方法 inverse="true"
        <set name="list" cascade="save-update,delete" inverse="true">
            <!--外键名称-->
            <key column="clid">
            </key>
            <one-to-many class="Contacter"/>
        </set>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容