Hibernate入门(一)

这篇博客介绍了Hibernate入门,从Hello World开始,逐步解析了核心API,包括save()、delete()、load()、get()、saveOrUpdate()和createQuery()的使用方法和区别,详细阐述了每个方法在操作数据库时的行为和注意事项。
摘要由CSDN通过智能技术生成

Hibernate入门(一)

一、Hello World

  1. 添加maven依赖

    <!-- hibernate -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.4.1.Final</version>
    </dependency>
    
    <!-- mysql connection -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.46</version>
    </dependency>
    
  2. 编写hibernate.cfg.xml文件

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE hibernate-configuration SYSTEM
            "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
    
    <hibernate-configuration>
        <session-factory>
            <!-- 告诉hibernate使用的是哪种数据库 -->
            <property name="hibernate.dialect">
                org.hibernate.dialect.MySQLDialect
            </property>
            <!--配置数据源-->
            <!-- 数据库驱动类 -->
            <property name="hibernate.connection.driver_class">
                com.mysql.jdbc.Driver
            </property>
    
            <!-- jdbc url -->
            <property name="hibernate.connection.url">
                jdbc:mysql://localhost:3306/test
            </property>
            <property name="hibernate.connection.username">
                root
            </property>
            <property name="hibernate.connection.password">
                11111
            </property>
    
            <!--是否显示sql-->
            <property name="show_sql">true</property>
            <!--格式化显示sql-->
            <property name="format_sql">true</property>
    
            <!-- List of XML mapping files -->
            <mapping resource="Employee.hbm.xml"/>
    
        </session-factory>
    </hibernate-configuration>
    
  3. 编写表与类,字段与属性的映射文件

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
    <!--
        做表与类的映射;
        一个hbm文件对应一张表和一个类的映射关系
    -->
    <hibernate-mapping>
        <!--name的值为:包名.类名,table为对应的表-->
        <class name="hibernate.Employee" table="EMPLOYEE">
            <!--元数据描述 可以去掉-->
            <!--<meta attribute="class-description">
                This class contains the employee detail.
            </meta>-->
            <!--
                id 指的是作为主键的字段,所以需要单独进行处理;
                name:属性名;
                column: 列名;
                type:字段的类型;
            -->
            <id name="id" type="int" column="id">
                <!--
                    这是主键的生成策略
                    increment:自增长
                        Oracle数据库,也可以配置increment
                        先查询要插入的表的id的最大值max,
                        执行max = max + 1,
                        将计算结果作为id。
                     sequence:序列
                     uuid:使用uuid算法生成主键
                     native:本地,hibernate自动根据数据库选择主键生成策略
                        mysql:increment
                        oracle: sequence,hibernate会默认使用一个叫做
                            hibernate_sequence的序列,而且该序列所有的pojo共享
                -->
                <generator class="native"/>
            </id>
            <property name="firstName" column="first_name" type="string"/>
            <property name="lastName" column="last_name" type="string"/>
            <property name="salary" column="salary" type="int"/>
        </class>
    </hibernate-mapping>
    
  4. 编写测试类

package hibernate;

// 实体类
public class Employee {
    private int id;
    private String firstName;
    private String lastName;
    private int salary;

    public Employee() {
    }

    public Employee(String fname, String lname, int salary) {
        this.firstName = fname;
        this.lastName = lname;
        this.salary = salary;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String first_name) {
        this.firstName = first_name;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String last_name) {
        this.lastName = last_name;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }
}
package hibernate;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class TestMain {
    private static SessionFactory factory = null;

    public static void main(String[] args) {
        // 读取hibernate的配置文件
        // 配置文件默认是根目录下的hibernate.cfg.xml文件
        Configuration config = new Configuration();
        // 如果配置文件的名字不是hibernate.cfg.xml
        // 可以使用重载方法,指定文件名。
        // config.configure("hibernate.xml");
        config.configure();

        // 创建sqlSessionFactory
        factory = config.buildSessionFactory();

        System.out.println("id1 = " + addEmployee("111", "222", 10000));
        System.out.println("id2 = " + addEmployee("aaa", "bbb", 20000));
        System.out.println("id3 = " + addEmployee("ccc", "ddd", 30000));

    }

    public static int addEmployee(String fname, String lname, int salary) {
        // 获取sqlsession
        Session session = factory.openSession();
        // 事务
        Transaction tx = null;
        Integer employeeId = null;
        try {
            // 开启事务
            tx = session.beginTransaction();
            Employee e = new Employee(fname, lname, salary);
            // 调用session API,插入到Employee表里,返回值为employeeId
            employeeId = (Integer) session.save(e);
            //提交事务
            tx.commit();
        } catch (HibernateException e) {
            // 发生异常,如果开启了事务,事务回滚
            if (tx != null) {
                tx.rollback();
            }
            System.err.println(("插入数据库失败  --- >" + e.getMessage()));
        } finally {
            session.close();
        }
        return employeeId;
    }
}

/*output :
Hibernate: 
    insert 
    into
        EMPLOYEE
        (first_name, last_name, salary) 
    values
        (?, ?, ?)
id1 = 4
Hibernate: 
    insert 
    into
        EMPLOYEE
        (first_name, last_name, salary) 
    values
        (?, ?, ?)
id2 = 5
Hibernate: 
    insert 
    into
        EMPLOYEE
        (first_name, last_name, salary) 
    values
        (?, ?, ?)
id3 = 6
*/

二、核心API

2.1 save()

​ 参考Hello World

保存执行结束,对象由临时态变成持久态

2.2 delete()

public static void delEmployee(int id) {
    //获取sqlsession
    Session session = factory.openSession();
    //事务
    Transaction tx = null;
    try {
        //开启事务
        tx = session.beginTransaction();
        // delete也是根据对象进行操作的。
        Employee e = new Employee();
        e.setId(id);
        session.delete(e);
        // 提交事务
        tx.commit();
    } catch (HibernateException e) {
        // 如果事务已经开启,回滚事务
        if (tx != null) {
            tx.rollback();
        }
        e.printStackTrace();
    } finally {
        // 关闭session
        session.close();
    }
}

首先我先清空了employee这张表,调用了delEmployee方法,会报错

Hibernate: 
    delete 
    from
        EMPLOYEE 
    where
        id=?
Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; statement executed: 

调用addEmployee()方法,在调用delEmployee()方法可删除成功。

        System.out.println("id1 = " + addEmployee("111", "222", 10000));
//        System.out.println("id2 = " + addEmployee("aaa", "bbb", 20000));
//        System.out.println("id3 = " + addEmployee("ccc", "ddd", 30000));

        delEmployee(1);

如果id为null,则不执行语句

删除的对象必须是 持久态对象或者 游离态对象

2.3 load()

根据id查询某个对象

/**
 * 根据id获取employee
 *
 * 这个方法,会报错, org.hibernate.LazyInitializationException: could not initialize proxy [hibernate.Employee#2] - no Session
 * load方法的执行则比较复杂首先查找session的persistent Context(一级缓存)中是否有缓存,
 * 如果有则直接返回,如果没有则去查找二级缓存,如果有则返回,
 * 如果没有则判断是否是lazy,若不是lazy,直接访问数据库检索,
 * 查到记录返回,并且同时在二级缓存中存放查到的数据方便下次使用,
 * 若再下次使用时在二级缓存命中,就是查到数据,则有可能将数据放到一级缓存中。
 * 若是lazy,则返回代理对象,查不到抛出异常,而不到数据库中查找,除非使用此对象时,才到数据库中查找
 *
 * @param id
 * @return
 */
public static Employee loadEmployeeById(Integer id) {
    //获取sqlsession
    Session session = factory.openSession();
    //事务
    Transaction tx = null;
    try {
        //开启事务
        tx = session.beginTransaction();
        Employee e = session.load(Employee.class, id);
        // 提交事务
        tx.commit();
        return e;
    } catch (HibernateException e) {
        // 如果事务已经开启,回滚事务
        if (tx != null) {
            tx.rollback();
        }
        e.printStackTrace();
    } finally {
        // 关闭session
        session.close();
    }
    return null;
}

这个方法,会报错, org.hibernate.LazyInitializationException: could not initialize proxy [hibernate.Employee#2] - no Session。load方法的执行则比较复杂首先查找session的persistentContext(一级缓存)中是否有缓存,如果有则直接返回,如果没有则去查找二级缓存,如果有则返回,如果没有则判断是否是lazy,若不是lazy,直接访问数据库检索,查到记录返回,并且同时在二级缓存中存放查到的数据方便下次使用,若再下次使用时在二级缓存命中,就是查到数据,则有可能将数据放到一级缓存中。若是lazy,则返回代理对象,查不到抛出异常,而不到数据库中查找,除非使用此对象时,才到数据库中查找。上述写法是打开一个新的session,session不一样,所以会报no session

如果id不存在,报错
No row with the given identifier exists: [类#ID]
如果实体(的hbm)没有映射到cfg中,报错
Unknown entity: 实体类

2.4 get()

/**
 * 根据id获取employee
 *
 * @param id
 * @return
 */
public static Employee getEmployeeById(Integer id) {
    //获取sqlsession
    Session session = factory.openSession();
    //事务
    Transaction tx = null;
    try {
        //开启事务
        tx = session.beginTransaction();
        Employee e = session.get(Employee.class, id);
        // 提交事务
        tx.commit();
        return e;
    } catch (HibernateException e) {
        // 如果事务已经开启,回滚事务
        if (tx != null) {
            tx.rollback();
        }
        e.printStackTrace();
    } finally {
        // 关闭session
        session.close();
    }
    return null;
}

/*output
Hibernate: 
    select
        employee0_.id as id1_0_0_,
        employee0_.first_name as first_na2_0_0_,
        employee0_.last_name as last_nam3_0_0_,
        employee0_.salary as salary4_0_0_ 
    from
        EMPLOYEE employee0_ 
    where
        employee0_.id=?
Employee{id=2, firstName='aaa', lastName='bbb', salary=20000}
*/

如果id不存在,返回null
如果实体(的hbm)没有映射到cfg中,报错
Unknown entity: 实体类

2.5 load()和get()的区别

  1. id不存在:

    1. load:报错
    2. get: 返回null
  2. 从检索执行机制上对比:

    1. load:

      load方法的执行则比较复杂首先查找session的一级缓存中是否有缓存,如果有则直接返回,如果没有则去查找二级缓存,如果有则返回,如果没有则判断是否是lazy,若不是lazy,直接访问数据库检索,查到记录返回,并且同时在二级缓存中存放查到的数据方便下次使用,若再下次使用时在二级缓存命中,就是查到数据,则有可能将数据放到一级缓存中。若是lazy,则返回代理对象,查不到抛出异常,而不到数据库中查找,除非使用此对象时,才到数据库中查找。

    2. get:

      get方法不能使用延迟加载,get方法先到一级缓存,然后二级,最后db查找。

2.6 update()

public static void updateEmployee(Integer EmployeeID, int salary ){
        Session session = factory.openSession();
        Transaction tx = null;
        try{
            tx = session.beginTransaction();
            Employee employee =
                    (Employee)session.get(Employee.class, EmployeeID);
            employee.setSalary( salary );
            session.update(employee);
            tx.commit();
        }catch (HibernateException e) {
            if (tx!=null) tx.rollback();
            e.printStackTrace();
        }finally {
            session.close();
        }
    }
    /*output
    Hibernate: 
    select
        employee0_.id as id1_0_0_,
        employee0_.first_name as first_na2_0_0_,
        employee0_.last_name as last_nam3_0_0_,
        employee0_.salary as salary4_0_0_ 
    from
        EMPLOYEE employee0_ 
    where
        employee0_.id=?
Hibernate: 
    update
        EMPLOYEE 
    set
        first_name=?,
        last_name=?,
        salary=? 
    where
        id=?
        
     */

如果ID不存在 , 报错

Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1

注意:如果重新创建了一个对象,其他列会被更新成null

Employee employee = new Employee();
employee.setId(2);
employee.setSalary(22000);

// fname,lname列会被更新为null

2.7 saveOrUpdate()

  • 如果对象id为null --­­­> save
  • 如果对象id不为null,并且在数据库中存在 --­­­> update
  • 如果对象id不为null,并且在数据库中不存在 ­­–> 报错

2.8 createQuery()

public static void getAllEmployees() {
    Session session = factory.openSession();
    Transaction tx = null;
    try {
        tx = session.beginTransaction();
        List<Employee> employees = session.createQuery("FROM Employee",Employee.class).list();
        Iterator<Employee> iterator = employees.iterator();
        while (iterator.hasNext()) {
            Employee employee = (Employee) iterator.next();
            System.out.print("First Name: " + employee.getFirstName());
            System.out.print("  Last Name: " + employee.getLastName());
            System.out.println("  Salary: " + employee.getSalary());
        }
        tx.commit();
    } catch (HibernateException e) {
        if (tx != null) tx.rollback();
        e.printStackTrace();
    } finally {
        session.close();
    }
}

/*
 * output
 * Hibernate:
 *     select
 *         employee0_.id as id1_0_,
 *         employee0_.first_name as first_na2_0_,
 *         employee0_.last_name as last_nam3_0_,
 *         employee0_.salary as salary4_0_
 *     from
 *         EMPLOYEE employee0_
 * First Name: 111  Last Name: 222  Salary: 15000
 * First Name: aaa  Last Name: bbb  Salary: 20000
 * First Name: ccc  Last Name: ddd  Salary: 30000
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值