Hibernate

Hibernate框架以完全面向对象的方式,提供了操作数据库的简便方法

1.数据库连接、实体类映射配置文件

注意,该配置文件必须放在src目录下,名称必须为hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
       "-//Hibernate/Hibernate Configuration DTD 3.0//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?characterEncoding=UTF-8</property>
        <property name="connection.characterEncoding">utf-8</property>
        <property name="connection.username">root</property>
        <property name="connection.password">123456</property>
        <!-- SQL dialect -->
        <!--本地方言,即告诉框架使用哪种数据库语言-->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <!--这是Hibernate事务管理方式,即每个线程一个事务-->
     <property name="current_session_context_class">thread</property>
        <!--这表示是否在控制台显示执行的sql语句-->
        <property name="show_sql">true</property>
        <!-- 这表示是否会自动更新数据库的表结构,有这句话,其实是不需要创建表的,
        因为Hibernate会自动去创建表结构 -->
        <property name="hbm2ddl.auto">update</property>
        <!--实体类映射配置文件路径,一个实体类一个配置文件-->
        <mapping resource="com/domain/Customer.hbm.xml" />
    </session-factory>
 
</hibernate-configuration>    

2.实体类配置文件

必须放在该实体类所在的包下,名称必须为 类名.hbm.xml,例如Customer.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 package="com.domain">
    <!-- name属性值对应类名 table属性值对应表名 -->
    <class name="Customer" table="cst_customer">
        <!-- 主键 实体类属性名 对应的字段名-->
        <id name="cust_id" column="cust_id">
            <!--  native意味着id的自增长方式采用数据库的本地方式 -->
            <generator class="native">
            </generator>
        </id>
        <!-- name属性值对应实体类属性名 column对应字段名,必须严格一一对应 -->
        <!--column属性可以不写,默认字段名为实体类属性名  -->
        <!-- 注意一点,有多少个字段名,在插入数据时,就会插入多少个字段值! -->
        <property name="cust_name"  column="cust_name" />
        <!--  <property name="cust_user_id" column="cust_user_id" />
        <property name="create_id" column="create_id"></property>
        <property name="cust_source" column="cust_source"></property>
        <property name="cust_industry" column="cust_industry"></property>
        <property name="cust_level" column="cust_level"></property>
        <property name="cust_linkman" column="cust_linkman"></property>
        <property name="cust_phone" column="cust_phone"></property>
        <property name="cust_mobile" column="cust_mobile"></property>-->
    </class>
     
</hibernate-mapping>

3.向数据库内插入一条数据

新建一个实体类Customer

public class Customer {
private long cust_id;
private String cust_name;
private long cust_user_id;
private long create_id;
private String cust_source;
private String cust_industry ;
private String cust_level;
private String cust_linkman;
private String cust_phone;
private String cust_mobile;
public Customer(long cust_id, String cust_name, long cust_user_id, long create_id, String cust_source,
        String cust_industry, String cust_level, String cust_linkman, String cust_phone, String cust_mobile) {
    super();
    this.cust_id = cust_id;
    this.cust_name = cust_name;
    this.cust_user_id = cust_user_id;
    this.create_id = create_id;
    this.cust_source = cust_source;
    this.cust_industry = cust_industry;
    this.cust_level = cust_level;
    this.cust_linkman = cust_linkman;
    this.cust_phone = cust_phone;
    this.cust_mobile = cust_mobile;
}
public Customer() {
    super();
}
@Override
public String toString() {
    return "Customer [cust_id=" + cust_id + ", cust_name=" + cust_name + ", cust_user_id=" + cust_user_id
            + ", create_id=" + create_id + ", cust_source=" + cust_source + ", cust_industry=" + cust_industry
            + ", cust_level=" + cust_level + ", cust_linkman=" + cust_linkman + ", cust_phone=" + cust_phone
            + ", cust_mobile=" + cust_mobile + "]";
}
public long getCust_id() {
    return cust_id;
}
public void setCust_id(long cust_id) {
    this.cust_id = cust_id;
}
public String getCust_name() {
    return cust_name;
}
public void setCust_name(String cust_name) {
    this.cust_name = cust_name;
}
public long getCust_user_id() {
    return cust_user_id;
}
public void setCust_user_id(long cust_user_id) {
    this.cust_user_id = cust_user_id;
}
public long getCreate_id() {
    return create_id;
}
public void setCreate_id(long create_id) {
    this.create_id = create_id;
}
public String getCust_source() {
    return cust_source;
}
public void setCust_source(String cust_source) {
    this.cust_source = cust_source;
}
public String getCust_industry() {
    return cust_industry;
}
public void setCust_industry(String cust_industry) {
    this.cust_industry = cust_industry;
}
public String getCust_level() {
    return cust_level;
}
public void setCust_level(String cust_level) {
    this.cust_level = cust_level;
}
public String getCust_linkman() {
    return cust_linkman;
}
public void setCust_linkman(String cust_linkman) {
    this.cust_linkman = cust_linkman;
}
public String getCust_phone() {
    return cust_phone;
}
public void setCust_phone(String cust_phone) {
    this.cust_phone = cust_phone;
}
public String getCust_mobile() {
    return cust_mobile;
}
public void setCust_mobile(String cust_mobile) {
    this.cust_mobile = cust_mobile;
}
}

实体类的基本数据类型请使用其包装类,因为框架生成对象,属性值有可能为null,如果是基本数据类型会报错。上例中如果把long修改为Long,但是get set 构造器没同步修改,会造成报错!

具体操作:

public class demo {
//Junit注释当前类为测试类
    @Test
    public void saveCustomer() {
        Configuration c = new Configuration();//加载配置文件
        c.configure();//加载配置文件
        //工厂模式
        SessionFactory factory = c.buildSessionFactory();
        Session session = factory.openSession();//开启一个会话
        Transaction transaction = session.beginTransaction();//开启事务
        Customer customer = new Customer();
        customer.setCust_name("Harry");
        session.save(customer);//保存
        transaction.commit();//提交
        session.close();//关闭会话
        factory.close();//关闭工厂
    }
    
}

 获取数据:

 Customer customer = session.get(Customer.class,1);

获取id为1的数据,封装为对象,利用该对象可以实现修改、删除等操作

注意,id数值类型一定要填写正确,例如id为Long,则应输入1L

修改:

 Customer customer = session.get(Customer.class,1);
 customer.setCust_name("张三");
 session.update(customer);

这里注意,即使不调用update方法,数据也会自行修改。

删除:

session.delete(customer);

2.Util封装

public class HibernateUtil {
    private static SessionFactory sf;
    static {
        //加载配置
        Configuration cfg = new Configuration().configure();//一定不要忘了调用configure方法,否则会报错!
        sf = cfg.buildSessionFactory();
    }
    //获取session
    public static Session openSession() {
        return sf.openSession();
    }
    //获取一个与当前线程绑定的Session
    public static Session getCurrentSession() {
        return sf.getCurrentSession();
    }
}

3.对象状态

public class TestDemo {
    @Test
    public void test() {
        Session session = HibernateUtil.openSession();
        Transaction transaction = session.beginTransaction();
        Customer  c = new Customer();
        c.setCust_name("张三");//瞬时状态
        session.save(c);//持久化状态
        transaction.commit();
        session.close();
       //脱管状态
    }
}        

瞬时状态:设置对象属性时,数据库中没有该条数据,此时对象是瞬时的。

持久化状态:此时对象存在于数据库,同时与session产生了联系,此时对象是持久化状态。

脱管状态:session关闭,对象与session失去联系,脱离了管理,此时对象是脱管状态。

4.一级缓存

@Test
    public void get() {
        Session session = HibernateUtil.openSession();
        Transaction transaction = session.beginTransaction();
        System.out.println("第一次查找");
        Customer c1 = (Customer)session.get(Customer.class, 1L);
        System.out.println("第一次查询对象哈希:"+c1.hashCode());
        System.out.println("第二次查找");
        Customer c2 = (Customer)session.get(Customer.class, 1L);
        System.out.println("第一次查询对象哈希:"+c2.hashCode());
        transaction.commit();
        session.close();
    }

输出结果:

第一次查找
Hibernate: select customer0_.cust_id as cust1_0_0_, customer0_.cust_name as cust2_0_0_, customer0_.cust_user_id as cust3_0_0_, customer0_.create_id as create4_0_0_, customer0_.cust_source as cust5_0_0_, customer0_.cust_industry as cust6_0_0_, customer0_.cust_level as cust7_0_0_, customer0_.cust_linkman as cust8_0_0_, customer0_.cust_phone as cust9_0_0_, customer0_.cust_mobile as cust10_0_0_ from cst_customer customer0_ where customer0_.cust_id=?
第一次查询对象哈希:1881561036
第二次查找
第一次查询对象哈希:1881561036

第一次查询后,对象被存入session一级缓存,如果后续操作还需要该对象,则直接从缓存中取该对象,对象哈希值一样。

快照:

连续修改两次数值

    @Test
    public void update() {
        Session session = HibernateUtil.openSession();
        Transaction transaction = session.beginTransaction();
        Customer c = (Customer)session.get(Customer.class, 2L);
        c.setCust_name("李四");
        c.setCust_name("小芳");
        //session.update(c);//可以不写
        transaction.commit();
        session.close();
    }

控制台输出:

Hibernate: select customer0_.cust_id as cust1_0_0_, customer0_.cust_name as cust2_0_0_, customer0_.cust_user_id as cust3_0_0_, customer0_.create_id as create4_0_0_, customer0_.cust_source as cust5_0_0_, customer0_.cust_industry as cust6_0_0_, customer0_.cust_level as cust7_0_0_, customer0_.cust_linkman as cust8_0_0_, customer0_.cust_phone as cust9_0_0_, customer0_.cust_mobile as cust10_0_0_ from cst_customer customer0_ where customer0_.cust_id=?
Hibernate: update cst_customer set cust_name=?, cust_user_id=?, create_id=?, cust_source=?, cust_industry=?, cust_level=?, cust_linkman=?, cust_phone=?, cust_mobile=? where cust_id=?

查询时,一个对象被放入session缓存,一个对象副本被存入快照区,当快照区的对象与缓存区的对象值不同时,数据被刷新到数据库,另外实际执行的语是是修改为小芳的那一条,如果我们先把名字改为小明,在改为李四(原始数据),则只会执行查询语句,因为快照区与缓存区内的对象没有变化。

这也就是之前我们没有执行uodate方法,数据依然会被更新的原因!

这样可以减少执行不必要的语句,提高效率。

 5.事务操作、隔离等级

为了防止并发操作引起的脏读、幻读等情况,要设置隔离等级 1,2,4,8

<!--这是Hibernate事务管理方式,即每个线程一个事务-->
<property name="current_session_context_class">thread</property>
获取session时要getCurrentSession,该种方式获取的session不要手动关闭,会自动关闭!
6.条件查询
HQL语言查询,hibernate自创的面向对象查询语言:
注意 from后面跟的是类名,不是表名!
@Test
    public void test2() {
        Session session = HibernateUtil.openSession();
        Transaction t = session.beginTransaction();
        //hql查询
        String hql = "from Customer";
        Query qr = session.createQuery(hql);
        List<Customer> customer = qr.list();
        System.out.println(customer);
        t.commit();
        session.close();
    }
    @Test
    public void test3() {
        Session session = HibernateUtil.openSession();
        Transaction t = session.beginTransaction();
        //hql条件查询
        String hql = "from Customer where cust_name=?";
        Query qr = session.createQuery(hql);
        qr.setParameter(0, "李四");//占位符开始位置基0
        Customer c = (Customer) qr.uniqueResult();
        System.out.println(c);
        t.commit();
        session.close();
    }
    @Test
    public void test4() {
        Session session = HibernateUtil.openSession();
        Transaction t = session.beginTransaction();
        //hql分页查询
        String hql = "from Customer";
        Query qr = session.createQuery(hql);
        qr.setFirstResult(0);
        qr.setMaxResults(2);
        List<Customer> customer = qr.list();
        System.out.println(customer);
        t.commit();
        session.close();
    }
使用Criteria进行数据查询 :Criteria 完全是 面向对象的方式在进行数据查询,将不再看到有sql语句的痕迹
  @Test
    public void test5() {
        Session session = HibernateUtil.openSession();
        Transaction t = session.beginTransaction();
        Criteria c = session.createCriteria(Customer.class);
        c.add(Restrictions.eq("cust_id", 2L));
        Customer customer = (Customer) c.uniqueResult();
        System.out.println(customer);
        t.commit();
        session.close();
    }

SQL原生查询:

    @Test
    public void test6() {
        Session session = HibernateUtil.openSession();
        Transaction t = session.beginTransaction();
        String sql = "select * from cst_customer";
        SQLQuery sq = session.createSQLQuery(sql);
        List<Object[]> list = sq.list();
        for(Object[] o:list) {
            System.out.println(Arrays.toString(o));
        }
        t.commit();
        session.close();
    }

结果封装为指定对象

    @Test
    public void test7() {
        Session session = HibernateUtil.openSession();
        Transaction t = session.beginTransaction();
        String sql = "select * from cst_customer";
        SQLQuery sq = session.createSQLQuery(sql);
        sq.addEntity(Customer.class);//封装为Customer对象
        List<Customer> list = sq.list();
        for(Customer c:list) {
            System.out.println(c);
        }
        t.commit();
        session.close();
    }
 
原文地址:https://www.cnblogs.com/whwjava/p/9107451.html