一: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中的缓存空间中。

最新文章

  1. UITabBarController
  2. 面向服务架构(SOA)和企业服务总线(ESB)
  3. RNN and LSTM saliency Predection Scene Label
  4. Django时间查询
  5. 【转】DataSource高级应用
  6. procedure can&#39;t return a result set in the given context
  7. java编程常用技术
  8. Become a Windows Insider and Test New Windows 10 Features
  9. 函数:递归是神马 - 零基础入门学习Python022
  10. Git 版本回退问题详解
  11. linux之SQL语句简明教程---IN
  12. [置顶] 深入浅出Spring(三) AOP详解
  13. ECMAScript 5中新增的数组方法
  14. 201521123076 《Java程序设计》第8周学习总结
  15. 第88节:Java中的Ajax和ASP.NET和TCP/IP 教程和JSON
  16. RMAN 的优缺点及RMAN 备份及恢复步骤
  17. day_6.22python多线程
  18. 《HTTP权威指南》读书笔记:缓存
  19. Java访问权限控制
  20. arc路径-磊哥

热门文章

  1. setInterval定时器停止后,再重新启动
  2. Java开发笔记(一百三十九)JavaFX的输入框
  3. 跨域和CORS
  4. Go语言 ( 切片)
  5. Java基础系列7——集合系列(1)框架概述
  6. Chart 文件结构
  7. 一张图看懂SharpImage
  8. Django:ORM介绍
  9. MySQL Connection--使用tcpkill杀掉MySQL活跃连接
  10. MySQL Index--NOT IN和不等于两类操作无法走索引?