• Java


    一:hibernate.cfg.xml 配置

    <!-- 1、配置数据库连接的4个参数 -->
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <!-- 连接数据库,本地数据库可以不用设置主机和端口 -->
    <property name="hibernate.connection.url">jdbc:mysql:///hibernate_01</property>
                                            <!-- jdbc:mysql://localhost:3306/数据库名 -->
    <!-- 用户名/密码 -->
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">chaoqi</property>
    
    <!-- 是否显示sql语句 -->
    <property name="show_sql">true</property>
    
    <!-- 是否格式化sql语句 -->
    <property name="format_sql">true</property>
    
    <!-- 是否自动提交事务:针对insert有效,针对delete无效 -->
    <property name="hibernate.connection.autocommit">true</property>
    
    <!-- 配置值 JavaBean 与表的映射文件 -->
    <mapping resource="com/q/hibernate/user.hbm.xml" />



    二:类 xml 配置

    <!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="com.q.hibernate.User" table="t_user">
            <!-- <id>: 与数据库对应id值, name: 类中id属性, column: 表中id属性 (类和表中的字段如果一样可以不用写 column) -->
            <id name="uid" column="id">
            <!-- 设置自增ID -->
                <generator class="native"></generator>
            </id>
    
            <!-- 添加字段(name, password) 由于数据库中字段名一样所以不用写 column 属性 -->
            <property name="username"></property>
            <property name="password"></property>
        </class>
    </hibernate-mapping>



    三:插入数据

    // 1. 获取核心配置对象,默认是加载src的hibernate.cfg.xml文件
        Configuration cfg = new Configuration().configure();
    
    // 2. 创建会话工厂
        SessionFactory factory = cfg.buildSessionFactory();
    
    // 3. 创建会话【相当于连接 Connect】
         Session session = factory.openSession();
    
    // 开启事务
        Transaction trans = session.getTransaction();
        trans.begin();
    
    // 实例化要插入数据的对象
        User user = new User();
        user.setUsername("q3");
        user.setPassword("123");
    
    // 保存在 session 中
        session.save(user);
            
    // 提交事务
        trans.commit();
    
    // 4. 关闭会话
        session.close();
    
    // 5. 关闭工厂,释放资源
        factory.close();




    四. sessionFactory 提供类两个方式获取 session

    1. factory.openSession()  # 获取一个权限的 session (重新开启一个新的线程, 需要手动 close )
     
    2. factory.getCurrentSession()    # 获取一个与当前线程绑定的 session (同一个线程里面调用返回同一个对象)

     - 配置:
     <property name="hibernate.current_session_context_class">thread</property>
      // 开启一个线程:
     new Thread(){
         public void run(){
             System.out.println("new thread");
         }
     }.start();



    五. Transaction 事务
    1. 默认需要手动提交事务:

    // 开启事务
        Transaction trans = session.getTransaction();
        trans.begin();
    // 提交事务
        trans.commit();


    2. 可在 hibernate.cfg.xml 文件中自动配置提交

    <!-- 是否自动提交事务:针对insert有效,针对delete无效 -->
    <property name="hibernate.connection.autocommit">true</property>



    5.5. session 的 get / load 方法
    1. 通过 id 获取数据
    2. get : 未找到数据返回 null (直接查询数据库)
    User user1 = (User) session.get(User.class, 1);

    3. load: 未找到数据报错 (懒加载,用到时才去查询数据库,返回的是对象的一个代理)
    User user2 = (User) session.load(User.class, 1);




    六. session 的 delete / update 方法

    1. update:

    // 如果是从数据库中获取的对象,会自动 update
    // 如:
    // User user = (User) session.get(User.class, 1);
    // user.setPassword("123");
    
    // 创建的对象需要手动更新
    User user = new User();
    user.setUid(1);
    user.setUsername("a");
    user.setPassword("b");
    
    session.update(user);    // 更新时, 一定要有id, 否则会出现异常
    session.saveOrUpdate(user);  // 有就更新,没有就创建



    2. delete : 需要手动提交事务

    // 开启事务
    session.getTransaction().begin();
    
    方式一:(创建一个 User,设置 id, 调用delete)
    User user = new User();
    user.setUid(1);
    session.delete(user);
    
    方式二:(获取删除对象,调用delete)
    User user = (User) session.get(User.class, 1);
    session.delete(user);
    
    // 提交事务
    session.getTransaction().commit();



    七. Query 查询 (HQL)    

    1. // 创建查询对象                        User      username   password
    Query query = session.createQeury("from 类名 where 字段=? and 字段?")
    query.setParameter(0, "a");
    query.setParameter(1, "b");
    
    // 执行 (返回一条数据)
    User user = (User) query.uniqueResult();



    2. 分页查询 limit

    // 创建查询对象
    Query query = session.createQuery("from User");
    
    // 分页查询 [limit 3,3]
    query.setFirstResult(3);  // 起始位置
    query.setMaxResults(3);   // 返回数据条数
    
    // 返回多条数据
    List<User> list = query.list();
    for(User obj : list){
        System.out.println(obj);
    }



    八. Criteria 查询 (条件查询)

    // 创建 Criteria 查询
    Criteria criteria = session.createCriteria(User.class);
    
    // 1.  eq : =
    criteria.add(Restrictions.eq("username","q"));
    criteria.add(Restrictions.eq("username","123"));
    System.out.println(criteria.uniqueResult());
    
    
    // 2.  gt 等于, ge 大于等于
    criteria.add(Restrictions.gt("id", 3));
    System.out.println(criteria.list());
    
    // 3. lt 小于,  le 小于等于
    
    // 4. like 模糊查询
    criteria.add(Restrictions.like("username", "%q%"));
    System.out.println(criteria.list());
    
    // 看文档...




    九. SQLQuery 查询 原生(SQL)

    // 查询
    SQLQuery query = session.createSQLQuery("select * from user");
    
    // 返回的数组封装到了集合,集合中是数组
    List<Object[]> list = query.list();
    for(Object[] objs : list){
        for(Object obj : objs){
            System.out.println(obj);
        }
    }




    十. hibernate 配置文件

    1. update : 更新,如果数据库没有表,会自动创建。
    2. create : 每次启动 hibernate 都会创建表。
    3. create-drop : 每次启动 hibernate 都会创建表,执行结束后会删除表。

    4. 数据库方言配置:

    mysql:
    <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</proterty>




    十一. 实体类 entity (model) 的编写规则 和  OID

    entity:
    1. 必须提供无参数的构造方法。
    2. 提供一个标识属性,映射数据库主键字段,提供id。
    3. 所有属性提供 public 访问控制符的 get/set 方法 (JavaBean)。
    4. 标识属性尽量使用包装类型。
    5. 不能使用 final 修饰实体 (将无法生成代理对象进行优化)。

    OID: 持久化对象的唯一标识  
    1. 对象的 OID 和 数据库中标的主键对应。


    十二. 主键生成

    < id name="id" column="id">
    
        1. native    : mysql 数据库自增, oracle数据库自增。
        2. uuid         : 需要将类中的 id 字段改为 字符类型,自动设置 uud。
        3. increment : 自增,hibernate 执行 select max(id) 查询,有并发问题。
        4. sequence  : oracle 数据库使用。
        5. assigned  : 需手动设置 id
    
        <generator class="native"></generator>
    </id>




    十三. hibernate 实体的状态

    三种状态:瞬时状态,持久状态,脱管状态

    1. 瞬时状态:transient, session 没有缓存,数据库没有记录,oid 没有值。
        load, get 返回持久对象,关闭session或清除后会变成脱管状态。
    2. 持久状态:persistent, session 有缓存,数据库有记录,oid 有值。
        使用 save, saveOrUpdate 。
    3. 脱管状态:detached, session 没有缓存,数据库有记录,oid 有值。



    十四. 一级缓存
    当获取一次 session ,hibernate 在 session 中创建多个集合,用于存放操作数据,优先从session缓存中获取,
    当 session 关闭时,一级缓存销毁。

    HQL / Criteria 有一级缓存
    SQL 没有一级缓存

    1. 使用 get 方法时会触发一级缓存,查询同一条语句时,只会执行一条 查询sql

    2. 清除缓存: session.clear(); / session.evict(s);

    3. 一级缓存快照:与一级缓存一样的存放位置,对一级缓存数据备份。保证数据库的数据与一级缓存中的数据一致,
    如果一级缓存修改了,在执行 commit 提交时,将自动刷新一级缓存,执行 update 语句,并更新到数据。

    4. 一级缓存刷新:手动刷新,让一级缓存的数据和数据库保持一致。

    sesson.flush();



    十五. save / persist

    1. save:
        // 执行save方法,触发 insert 语句,从数据库获取主键。
        // 执行save前,设置oid会被忽略。
        // 如果执行查询,session缓存被清除了,再次执行save方法,将执行 insert

    2. persist
        // 保存对象前,不能设置 Id ,否则报错。
        // 在事务外部调用不会执行 insert ,在事务内部中结束后执行 insert。



    十六. 一对多

    1. Customer

     private Integer id;
        private String name;
    
        // 一对多属性描述
        private Set<Order> orders = new HashSet<Order>();


    2. Order

        private Integer id;
        private String name;
    
        private Customer customer;




    3. customer.hbm.xml

    <hibernate-mapping package="domain">
        <class name="Customer" table="t_customer">
            <id name="id">
                <generator class="native" />
            </id>
            
            <property name="name" />
    
            <!--
                cascade : 级联
                    save-update : 级联保存,级联修改,保存A的同时保存B。
                    delete :  级联删除,删除A的同时删除B。(先删B,再删A)
                    delete-orphan : 删除A关联的B ,但不删除A
    
                    all = [ save-update, delete ] (级联保存, 级联删除)
                    all-delete-orphan = [ save-update, delete, delete-opphan ]
    
             -->
            <set name="orders" cascade="all-delete-orphan">
                <key column="customer_id"></key>
                <one-to-many class="Order"></one-to-many>
            </set>
        </class>
    </hibernate-mapping>



    4. order.hbm.xml

    <hibernate-mapping package="domain">
        <class name="Order" table="t_order">
            <id name="id">
                <generator class="native" />
            </id>
            
            <property name="name" />
            
            <many-to-one name="customer" class="Customer" column="customer_id" />
            
        </class>
    </hibernate-mapping>



    # 一对多操作
    5. 创建数据

    // 0. 开启事务
    session.getTransaction().begin();
    
    // 1. 创建客户对象
    Customer customer = new Customer();
    customer.setName("q");
    
    // 2. 创建订单对象
    Order order1 = new Order();
    order1.setName("商品1");
    Order order2 = new Order();
    order2.setName("商品2");
    
    // 3. 给订单建立客户关系
    order1.setCustomer(customer);
    order2.setCustomer(customer);
    
    // 4. 给客户添加订单
    customer.getOrders().add(order1);
    customer.getOrders().add(order2);
    
    // 5. 保存数据
    session.save(customer);
    session.save(order1);
    session.save(order2);
    
    // 6. 结束事务
    session.getTransaction().commit();





    6. 查询数据

    Customer customer = (Customer) session.get(Customer.class, 1);
    
    // 获取用户
    String customer1 = customer.getName();
    System.out.println(customer1);
    
    
    // 获取用户当前所有订单
    Set<Order> orders = customer.getOrders();
    for(Order order : orders){
        System.out.println(order.getName());
    }




    7. 删除数据
     

    Customer customer = (Customer) session.get(Customer.class, 1);
    
    session.getTransaction().begin();
    
    // 更新订单
    for(Order order : customer.getOrders()){
        order.setCustomer(null);
    }
    
    // 删除用户
    session.delete(customer);



    8. 级联更新

    Customer customer = new Customer();
    customer.setName("q");
    
    Order order1 = new Order();
    Order order2 = new Order();
    order1.setName("d1");
    order2.setName("d2");
    
    order1.setCustomer(customer);
    order2.setCustomer(customer);
    
    customer.getOrders().add(order1);
    customer.getOrders().add(order2);
    
    session.save(customer);




    9. 级联删除 先删 B 再删 A

    session.getTransaction().begin();
    
    Customer customer = (Customer) session.get(Customer.class, 2);
    session.delete(customer);
    
    session.getTransaction().commit();



    10. 级联删除 删除与A关联的B 但是不删除 A

    session.getTransaction().begin();
    
    Customer customer = (Customer) session.get(Customer.class, 1);
    
    Set<Order> orders = customer.getOrders();
    Iterator<Order> iterator = orders.iterator();
    
    while(iterator.hasNext()){
        iterator.next();  // 取出下一个元素
        iterator.remove(); // 移除当前元素
    }
    
    session.getTransaction().commit();



    十七. 多对多

    1. Order

    private Integer id;
    private String name;
    
    private Customer customer;



    2. Course

    private Integer cid;
    private String name;
    private Set<Student> students = new HashSet<Student>();



    3. Student.hbm.xml

    <hibernate-mapping package="domain">
        <class name="Order" table="t_order">
            <id name="id">
                <generator class="native" />
            </id>
            
            <property name="name" />
            
            <many-to-one name="customer" class="Customer" column="customer_id" />
            
        </class>
    </hibernate-mapping>



    4. Course.hbm.xml

    <hibernate-mapping package="domain">
        <class name="Course" table="t_course">
            <id name="cid" column="id">
                <generator class="native"></generator>
            </id>
    
            <property name="name" />
    
            <set name="students" table="t_student_course" cascade="save-update">
                <key column="cid"></key>
                <many-to-many class="Student" column="sid" />
            </set>
    
        </class>
    </hibernate-mapping>





    # 多对多操作

    注意事项:
         1. 在xml配置文件中  set 属性要加上: cascade="save-update" 才会自动创建表
         2. 如果在 Student配置 inverse="true", 由Course来维护外键关系,中间表没数据。
         3. 默认Student配置 inverse="false", 由 Student来维护外键关系,中间表有数据。
         4. 多对多,inverse 不能两边都为 true, 如果两边都为 true, 不管保存哪个对象,中间表都没数据。

    5. 创建数据

    session.getTransaction().begin();
    
    // 创建学生对象
    Student stu1 = new Student("ming");
    Student stu2 = new Student("pang");
    
    // 创建课程对象
    Course c1 = new Course("Java");
    Course c2 = new Course("Python");
    
    // 将课程绑定学生
    stu1.getCourses().add(c1);
    stu1.getCourses().add(c2);
    
    stu2.getCourses().add(c1);
    stu2.getCourses().add(c2);
    
    // 创建保存
    session.save(stu1);
    session.save(stu2);
    
    session.getTransaction().commit();




    6. 查询

    Student stu1 = (Student) session.get(Student.class,3);
    
    System.out.println(stu1);
    System.out.println(stu1.getCourses());
    
    // Set<Course> courses = stu1.getCourses();
    // System.out.println(courses);




    十八. 锁

    1. 写锁
    当线程A拿到 数据行 d 的锁时,其它线程无法对 数据行 d 进行操作,会阻塞住,直到线程A释放(commit)。

    session.getTransaction().begin();
    
    //Hibernate的写锁/排他锁实现
    /**
     * 演示客户名,查找id为1
     * A线程【命令行】,开启事务->读取一行数据加锁
     * B线程【应用程序】,开启事务->读取一行数据加锁
     */
    
    //执行sql语句,使用写锁
    /*Customer customer = (Customer) session.get(Customer.class,1, LockOptions.UPGRADE);
    System.out.println(customer);*/
    
    /**
     * HQL的from后面不能写for update
     * 调用query.setLockOptions(LockOptions.UPGRADE);
     */
    Query query = session.createQuery("from Customer where id=?");
    query.setLockOptions(LockOptions.UPGRADE);
    query.setParameter(0,1);
    
    Customer customer  = (Customer) query.uniqueResult();
    System.out.println(customer);
    
    session.getTransaction().commit();




    2. 乐观锁
    在数据库增加一个字段(verson),每次更新不同的数据会对字段值+1(verson+1) ,
    如果本次更新值后verson+1 小于数据中verson值,那么会报错。

    # 需要配置 XML 中的 verson

    <!--version 放在id和property的中间,这个由dtd约束决定-->
    <version name="version"></version>


    # 操作

    session.getTransaction().begin();
    
    //乐观锁:每次更新,版本会加1
    /**
     * 如果当前的版本【2】比数据库【3】低,就不更新,出错
     * 乐观锁是hibernate自己实现
     * for update 是mysql实现
     */
    Customer customer = (Customer) session.get(Customer.class,1);
    customer.setName("abc232");
    
    session.getTransaction().commit();


    十九. 一对一

    1. Company

        private Integer id;
        private String name;
        private Address address;


    2. Address

        private Integer id;
        private String name;
        private Company company;


    3. Company.hbm.xml

    <class name="Company" table="t_company">
        <id name="id" column="id">
            <generator class="native"></generator>
        </id>
    
        <property name="name" />
    
        <one-to-one name="address" class="Address"></one-to-one>
    
    </class>



    4. Address.hbm.xml

    <class name="Address" table="t_address">
        <id name="id" column="id">
            <!-- 主键又是外键 -->
            <generator class="foreign">
                <param name="property">company</param>
            </generator>
        </id>
    
        <property name="name" />
        
        <many-to-one name="company" class="Company" column="company_id" unique="true"></many-to-one>
    
        <!-- 设置主键就是外键 -->
        <!--<one-to-one name="company" class="Company" constrained="true"></one-to-one>-->
    
    </class>


    # 一对一操作
    5. 创建数据

    session.getTransaction().begin();    
    
    Company company1 = new Company();
    company1.setName("Ali");
    
    Address address1 = new Address();
    address1.setName("China");
    address1.setCompany(company1);
    
    session.save(company1);
    session.save(address1);
    
    session.getTransaction().commit();


    6. 查询数据

    Company company = (Company) session.get(Company.class, 1);
    
    System.out.println(company.getName());
    System.out.println(company.getAddress().getName());




    二十. c3p0 连接池(配置在 hibernate.cfg.xml)

    <!-- 配置 c3p0 -->
    <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
    <property name="hibernate.c3p0.max_size">2</property>
    <property name="hibernate.c3p0.min_size">2</property>
    <property name="hibernate.c3p0.timeout">5000</property>
    <property name="hibernate.c3p0.max_statements">100</property>
    <property name="hibernate.c3p0.idle_test_period">3000</property>
    <property name="hibernate.c3p0.acquire_increment">2</property>
    <property name="hibernate.c3p0.validate">false</property>



    二十一. 二级缓存

    1. 类缓存:
    查询后会在类缓存中存储这个类对象,再次查询的时候会匹配查询类和缓存中的类对象是否一致,然后返回结果,没有则去数据库。

    2. 集合缓存
    在集合缓存中存储的是类id,然后通过id去类缓存中找匹配的类对象,然后返回结果,没有则去数据库。

    3. 查询缓存
    需要手动开启缓存,可以在不同的 session 中获取类对象,其还是去类缓存中查找。

    4. 时间戳缓存
    会将本次查询和上次查询进行匹配,如果一致则不去数据库查,直接返回上次结果。

    5. ehache 缓存
    如果缓存大小溢出,那么就会存储到ehache中的缓存空间中。



  • 相关阅读:
    MySQL数据库8(四)数据表基本操作
    MYSQL 配置文件
    MySQL数据库8(三)数据库基本操作
    flink-connector-kafka consumer的topic分区分配源码
    kafka consumer assign 和 subscribe模式差异分析
    kafka 配置kerberos校验以及开启acl实践
    二路归并排序的java实现
    storm RollingTopWords 实时top-N计算任务窗口设计
    PriorityBlockingQueue优先队列的二叉堆实现
    堆排序算法的java实现
  • 原文地址:https://www.cnblogs.com/chaoqi/p/10699484.html
Copyright © 2020-2023  润新知