hilbernate 框架
Hibernate 是框架的意思:
框架是什么?
框架是为了提高开发效率.
框架中封装好了一些功能, 我们需要使用这些功能的时候, 直接调用即可, 不在需要自己去实现(半成品).
所以框架可以理解为一个半成品的项目, 只要懂得如何驾驭这些功能即可.
一个项目 被分为3个部分组成 web层 , Service层 , dao层; Hibernate(代替dao层) 将代替JDBC , DBUtil 层 Struts2(代替web层) 将代替Servlet , JSP 层 service层里面是 javaBean Spring 将包裹上面2个框架 Spring 项目的容器, 负责管理项目中的所有对象. Spring可以理解为管家.
Hibernate 的好处, 操作数据库的时候以面向对象的方式完成, 不在需要书写SQL语句.Hibernate是一款ORM的框架, ORM : object relation mapping(对象 关系映射);ORM 分为四级: (Hibernate 属于最顶级的ORM 框架,完全属于面向对象的框架) Hibernate属于四级 , 完全"面向对象"操作数据库. (三级没有) Mybatis 属于二级 DBUtils 属于一级
Hibernate 概述:
1.什么是框架:
写一个程序, 使用框架之后会帮我们实现一部分功能, 少写一部分到吗, 就能实现某种功能.
2.什么是hibernate框架(重点):
1.hibernate框架应用在javaee三层结构中dao层框架. 2.在dao层里面做对数据库crud操作, 使用hibernate实现crud操作, hibernate底层代码就是JDBC,hibernate对JDBC进行封装, 使用hibernate好处, 不需要写复杂的JDBC的代码,不需要写sql语句也能实现. 3.hibernate开源轻量级框架, 免费 源代码开源 不需要引用太多的jar包和其他的引用. 4.hibernate版本 3.x 4.x(过度产品) 5.x(学习) hibernate框架包中: documentation : 文档部分 lib : hibernate相关的jar包 project : 里面的源代码部分
3.什么是orm思想:
1.hibernate使用orm思想对数据库进行crud操作. 2.在web阶段学习javabean.更正确的叫法 实体类. 3.orm:对象关系映射 o: object 对象 r: relation 关系 m: mapping 映射
文字描述:
(1).让实体类和数据库表进行一一对应关系. 让实体类首先和数据库对应 让实体类属性 和 表里面字段对应.(2).不需要直接操作数据库表, 而操作表对应实体类操作.
//JDBC代码: //加载驱动 Class.forName("com.mysql.jdbc.Driver"); //创建连接: Connection conn = DriverManager.getConnection(url,username,password); //对sql进行预编译操作: PreparedStatment ps = conn.preparedStatement(sql); //执行sql,查询sql String sql = "select * from user"; ResultSet rs = ps.executeQuery(); //遍历结果集 ...... //释放资源 ......
orm思想:
//实体类: public class User{ private int id; private String username; private String password; //set get方法 …… }
//表的内容 create table t_user( uid id, username varchar(100), password varchar(100) ) //让实体类与表进行一一对应: 类和表对应, 类里面的属性和表里面的字段对应, (不需要写代码,使用配置文件完成) //不需要操作表, 而操作表对应的实体类对象可以了. hibernate封装的对象Session //创建实体类的对象: User user = new User(); user.setUsetname("小米"); session.save(user);
注意: 在框架阶段会使用很多的配置文件;
Hibernate 配置文件:
hibernate配置文件详解:
hibernhate 映射配置文件:
1.映射配置文件的名称和位置没有固定要求2.映射配置文件中, 标签 name属性值写实体类相关内容; (1).class 标签name属性实体类全路径 (2).id 标签和 property 标签name属性 实体类属性名称;3..id标签和property标签, column 属性可以省略的 (1).不写值金额name属性一样的4.property标签type属性, 设置生成表字段的类型, 自动对应类型;
hibernate 核心配置文件:
1.配置写位置在<hibernate-factory>标签里面2.配置三部分要求: (1).数据库部分必须的 (2).hibernate部分可选的 (3).映射文件必须的3.核心配置文件名称和位置是固定的 (1).位置: src下面 (2).名称: hibernate.cfg.xml
Hibernate 的API的使用:
Configuration
1.代码:
Configuration cfg = new Configuration().configure();(1).到src下面找到名称hibernate.cfg.xml配置文件,创建对象, 把配置文件放到对象里面(加载核心配置文件)
SessionFactory(重要)
1.使用configuration对象创建sessionFactory对象; (1).创建sessionfactory过程中做事情 根据核心配置文件中, 有数据库配置, 有映射文件部分, 到数据库里面根据映射关系, 将表创建(注意: 在核心配置文件中必须写下面配置才能自动创建); <property name="hibernate.hbm2ddl.auto">update</property>2.创建sessionFactory过程中, 这个过程特别耗资源的 (1).在hibernate操作中,建一个项目一般创建一个sessionFactory对象.3.具体实现(写一个工具类) (1).写工具类, 写静态代码块实现 静态代码块在类加载时候执行, 执行一次. HibernateUtils.java ==> com.yao.utils.HibernateUtils
Session(重点)
1.session类似于jdbc Connection连接2.调用session里面不同的方法实现crud操作; (1).添加sace方法 (2).修改update方法 (3).删除delete方法 (4).根据id查询get()方法3.session对象单线程对象. (1).session对象不能共有, 只能自己使用
Transaction
1.事物对象: Transaction ts = session.beginTransaction();2.事物提交和回滚方法: ts.commit(); //提交 ts.rollback();//回滚3.事物概念: (1).事物的四个特性: 原子性: 一组操作, 要么都成功,只要有一个失败, 事物就无法成功 一致性: 操作之前之后, 数据要一致 隔离性: 多个事物同时操作同一组数据, 之间不会产生影响 持久性: 最终事物要commit提交, 事物生效叫做持久性
解决配置文件没有提示的问题:
1.可以上网2.把约束文件引入到eclipes 里面 window ==> 最后一个 ==> 搜索xml c (1).在配置文件中复制一句话 http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd (2).URI 将上面的路径和 mapping文件的路径复制进去.
实体类的编写规则(重点):
1.实体类的属性必须是私有的2.私有属性必须使用GetSet方法操作3.要求实体类里面要有一个属性作为一个唯一值(一般都使用id值);4.实体类属性, 建议不使用基本数据类型, 使用基本数据类型对应的包装类; (1).八个基本数据类型对应的包装类; int = Integer char = character 其他的都是首字母大写 double = Double (2).比如 表示学生的分数, 假如int score 比如这个学生得了0分, int score = 0; 比如表示学生没有参加考试, int score = 0;(不能准确表示学生是否参加考试) 解决方法: 使用包装类, Integer score = 0,(表示学生得了0分) 表示学生没有参加考试, Integer score = null;
hibernate 主键生成策略:
1.hibernate要求实体类里面有一个属性作为唯一值, 对应表主键, 主键可以不同生成策略2.hibernate 主键生成策略有很多的值. <generator class="native"></generator>3.在上面标签的class属性里面. increment: 每次自增一 identity: (在Oracle里面不能使用),代理主键, 使用条件为主键定义为自增长类型 sequence: 支持生成序列,只能在Oracle里面使用 native(重要): 根据使用的数据库,会自动帮你选择用那个值 uuid(重要): 之前web阶段,需要写代码生成uuid值, hibernate帮我们生成uuid值 (1).使用uuid生成策略, 实体类id属性 必须 字符串类型 (2).配置部分uuid值;(不写值会生成十六进制数字) assigned:
实体类操作:
1.crud操作(重点):
添加操作:
1.调用session里面的save方法实现:
User user = new User(); user.setUsername("小yooo"); user.setPassword("2333"); user.setAddress("越南"); //调用session1实现添加 session.save(user);
根据id查询:
1.调用session里面的get方法;
//调用session里面的get方法 //第一个参数:实体类的class //第二个参数: 要查询id的值 User user = session.get(User.class, 1); System.out.println(user);
修改操作:
1.首先查询,再修改
(1).先根据id查询,返回对象 //4.添加操作 //第一步: 根据id查询 User user = session.get(User.class, 2); //第二步: 向返回的user对象里面设置修改之后的值 user.setUsername("york"); //第三步:调用session里面update方法修改 //执行过程: 到user对象里面找到uid的值,根据id修改 session.update(user);
删除操作:
1.调用session里面的delete方法实现:
//第一种方式: 根据id查询对象 User user = session.get(User.class, 2); session.delete(user); //第二种方法: User user = new User(); user.setUid(3); session.delete(user);
2.实体类对象状态(概念):
1.实体类有三种状态:
(1).瞬时态
//对象里面没有id值,与session没有关联 //例: User user = new User(); user.setUsername("小yooo"); user.setPassword("2333"); user.setAddress("越南");
(2).持久态
//对象里面有id值, 与session有关联 //例: User user = session.get(User.class, 1);
(3).托管态
//对象里面有id值, 与session没有关联 //例: User user = new User(); user.setUid(3);
2.演示操作实体类的操作:
(1).saveOrUpdate方法: 实现添加, 实现修改.
User user = new User(); user.setUsername("jack"); user.setPassword("666"); user.setAddress("越南"); //实体类对象状态是瞬时态, 则进行添加操作 session.saveOrUpdate(user); User user = new User(); user.setUid(2); user.setUsername("jim"); user.setPassword("2222"); user.setAddress("北京"); //实体类状态为托管态的时候, 则进行修改操作 session.saveOrUpdate(user); User user = session.get(User.class, 1); user.setUsername("tom"); //实体类为持久态的时候, 则进行修改操作 session.saveOrUpdate(user);
hibernate 的一级缓存
什么是缓存:
1.数据存到数据库里面, 数据库本身是文件系统, 使用流方式操作文件效率不是很高. (1).把数据存到内存中, 不需要使用流的方式, 可以直接读取内存中数据 (2).把数据放到内存中, 提供读取效率
hibernate 缓存
1.hibernate框架中提供了很多优化, hibernate 的缓存就是一个优化方法.2.hibernate 缓存特点: 第一类: hibernate 的一级缓存 (1).hibernate 的一级缓存默认就是打开的. (2).hibernate 的一级缓存有使用范围.是session的范围, 从session创建到session关闭范围 (3).hibernate 的一级缓存中, 存储数据必须是 持久态数据
第二类: hibernate 的二级缓存 (1) 目前已经不使用了, 替代技术 redis (2)二级缓存默认不是打开的, 需要配置 (3)二级缓存使用范围, 是sessionFactory范围.
验证一级缓存存在: 1.验证方式: (1)首先根据uid=1查询, 返回对象 (2)其次再根据uid=1查询, 返回对象
//1.根据uid=1查询 //执行了第一个get方法后是否会查询数据库, 是否发送sql语句 User user1 = session.get(User.class, 1); System.out.println(user1); //2.再根据uid=1查询 ////执行了第二个get方法后是否会查询数据库, 是否发送sql语句 User user2 = session.get(User.class, 1); System.out.println(user2); /* 结果: Hibernate: select user0_.uid as uid1_0_0_, user0_.username as username2_0_0_, user0_.password as password3_0_0_, user0_.address as address4_0_0_ from t_user user0_ where user0_.uid=? User [uid=1, username=小王, password=6666, address=日本] User [uid=1, username=小王, password=6666, address=日本] */
结论:
第一次执行了get方法之后, 发送sql语句查询数据库 第二次执行get方法之后,没有发送sql语句查询数据库
hibernate 一级缓存执行过程
1.首先查询一级缓存, 查询一级缓存有没有数据, 没有就去查询数据库, 然后user1对象(持久态对象) 其次, 把user1持久态对象放到一级缓存中2..user2 ,再次查询, 先查询一级缓存, 发现一级缓存有相同的数据, 直接返回
hibernate 一级缓存特性:
1.持久态自动更新数据库;
//执行操作 //1.根据id查询 User user = session.get(User.class, 1);//持久态对象 //2.设置返回对象值 user.setUsername("hanmeimei"); //3.调用update方法 //session.update(user);
2.执行过程(了解):
一旦创建session, 就会出现一级缓存, 而在一级缓存出现, 这会有一块对应的区域出现 快照区(副本)
hibernate事务操作
事务相关概念:
1.什么是事务
要么都成功, 要么都失败;(银行转账就是最好的例子)
2.事务特性:
原子性,一致性,隔离性,持久性
3.不考虑隔离性产生问题
(1).脏读(2).不可重复读(3).虚读
4.设置事物隔离级别
(1).MySql默认的隔离级别 REPEATABLE_READ (repeatable_read)
hibernate 事务代码规则写法(重点):
1.结构代码
try{ 开启事物 提交事物 }catch{ 回滚事物 }finally{ 关闭 }
@Test public void testTx(){ SessionFactory sessionFactory = null; Session session = null; Transaction tx = null; try { //得到sessionFactory sessionFactory = HibernateUtils.getSessionFactory(); //开启session session = sessionFactory.openSession(); //开启事务 tx = session.beginTransaction(); //添加 User user = new User(); user.setUsername("Tom"); user.setPassword("3322"); user.setAddress("美国"); session.save(user); //提交事物 tx.commit(); } catch (Exception e) { e.printStackTrace(); //出现异常回滚事务 tx.rollback(); }finally { //关闭事务 session.close(); sessionFactory.close(); } }
hibernate 绑定 session
1.session 类似与JDBC的connection, 之前web阶段学过threadLocal2.帮我们实现与本地线程绑定的session3.获取与本地线程绑定的session (1).在hibernate核心配置文件中配置 <!-- 配置与本地线程绑定的session --> <property name="hibernate.current_session_context_class">thread</property> (2).调用sessionFactory里面的方法 //提供返回与本地线连接的session方法 public static Session getSessionobject(){ return sessionFactory.getCurrentSession(); }4.获取与本地线程绑定session时候, 关闭session报错, 当获取本地session绑定的时候, 就不需要手动关闭了. 会有异常出现: Session was already closed
hibernate 其他API查询(重点):
Query对象
1.使用Query对象, 不需要使用sql语句, 但是写hql语句 (1).hql: h: hibernate; q: query; l:language; 这个hql语句和普通sql语句很相似. (2).hql和sql的区别: 使用普通的sql操作表和表字段. 使用hql操作实体类和实体类的属性. 2.查询所有hql语句 (1). from 实体类的名称;3.Query 对象的使用 (1).创建一个Query对象 (2).调用Query对象里面的方法得到结果
//1.创建Query对象 Query query = session.createQuery("from User"); //2.调用Query对象里面的方法得到结果 List<User> list = query.list(); for (User user : list) { System.out.println(list); }
Criteria对象
1.使用这个对象查询到操作, 但是使用这个对象时, 不需要写语句, 直接调用方法实现2.实现过程: (1).创建criteria对象 (2).调用方法得到结果
//1.创建Criteria对象 //方法里面的参数是实体类的class Criteria criteria = session.createCriteria(User.class); //调用方法得到结果 List<User> list = criteria.list(); for (User user : list) { System.out.println(user); }
SQLQuery对象
1.使用hibernate时候, 调用底层sql实现.2.实现过程: (1).创建SQLQuery对象 (2).调用方法得到结果
//1.创建SQLQuery对象 //参数就是普通的sql语句 SQLQuery SQLQuery = session.createSQLQuery("select * from t_user"); //调用SQLQuery里面的方法; //返回的list集合, 默认里面每部分数组结构 List<Object[]> list = SQLQuery.list(); for (Object[] objects : list) { //Arrays.toString() 可以把数组作为字符串输出. System.out.println(Arrays.toString(objects)); }
注意: 返回的list集合是数组;
返回list中每部分是对象形式:
//1.创建SQLQuery对象 //参数就是普通的sql语句 SQLQuery SQLQuery = session.createSQLQuery("select * from t_user"); //返回的list中每部分是对象形式 //设置数据 ,放到那个实体类中 SQLQuery.addEntity(User.class); //调用SQLQuery里面的方法 List<User> list = SQLQuery.list(); for (User user : list) { System.out.println(user); }
注意: 返回的结果 是对象形式.
表与表之间关系回顾:
1.一对多
(1).分类和商品的关系, 一个分类里面有多个商品, 一个商品只能属于一个分类; (2).客户和联系人是一对多关系 客户: 与公司有业务往来, 百度, 新浪, 360 联系人: 公司里面的员工, 百度里面有很多的员工, 联系员工 公司和公司员工的关系. 客户是一, 联系人是多. 一个客户里面有多个联系人, 一个联系人只能属于一个客户. (3).一对多建表, 通过外键.
2.多对多
(1).订单和商品关系, 一个订单里面有多个商品, 一个商品属于多个订单 (2).用户和角色多对多的关系. 用户: 小王,小马,小宋. 角色: 总经理,秘书,司机,保安. 比如小王 可以是总经理, 也可以是司机 比如小宋 可以是司机, 可以是秘书, 可以是保安 比如小马 可以是秘书, 可以是总经理. 一个用户里面可以有多个角色, 一个角色里面可以有多个用户. (3)多对多, 创建第三张表来维护之间的关系 第三张表至少有两个字段作为外键, 指向两个表主键.
3.一对一
(1)在中国, 一个男人只能有一个妻子, 一个女人只能有一个丈夫.
(1).一对多(客户和联系人)(2).多对多(用户和角色)
hibernate 一对多操作:
(1).一对多映射配置
(以客户和联系人为例,客户是一,联系人是多) 第一步:导入jar包 第二步:创建实体类(两个,一个客户的,一个联系人) 第三步:让这两个实体类之间相互表示. (1).在客户实体类里面表示多个联系人. 一个客户里面多个联系人.
//在客户实体类里面表示多个联系人, 一个客户有多个联系人. //hibernate要求使用集合表示多的数据,使用set集合. private Set<LinkMan> setLinkMan = new HashSet<LinkMan>(); public Set<LinkMan> getSetLinkMan() { return setLinkMan; } public void setSetLinkMan(Set<LinkMan> setLinkMan) { this.setLinkMan = setLinkMan; }
(2).在联系人实体类里面表示所属客户.
一个联系人只能属于一个客户.
//在联系人里面表示所属客户,一个联系人只能属于一个客户. private Customer customer; public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; }
第四步: 配置映射关系:
(1).一个实体类对应一个映射文件(2).把映射最基本的配置完成(3).在映射文件中,配置一对多的关系 在客户的映射文件中,表示所有的联系人
<!-- 在客户的映射文件中,表示所有的联系人 使用set标签表示所有的联系人 set标签里面有name属性, 属性值写在客户实体类里面表示联系人的set集合名称 --> <set name="setLinkMan"> <!-- 一对多建表,有外键. hibernate机制, 双向维护外键, 在一和多那一方都配置外键. column属性值就是外键的名称 --> <key column="clid"></key> <!-- 客户所有的联系人,class里面写联系人实体类的全路径 --> <one-to-many class="com.yao.entity.LinkMan"/> </set>
在联系人中,表示所属的客户.
<!-- 表示联系人所属的客户 name属性: 因为在联系人实体类使用customer对象表示,写customer名称 class属性: customer全路径 column属性: 外键的名称clid --> <many-to-one name="customer" class="com.yao.entity.Customer" column="clid"></many-to-one>
第五步:创建核心配置文件, 把映射文件映入到核心配置文件中
<mapping resource="com/yao/entity/Customer.hbm.xml"/> <mapping resource="com/yao/entity/LinkMan.hbm.xml"/>
第六步: 测试, 执行工具类
级联操作:
(2).一对多级联保存
1.级联保存 (1).添加了客户, 为这个客户添加了多个联系人
(添加客户,为这个客户添加一个联系人)
//添加一个客户,为这个客户添加一个联系人. //1.创建客户跟联系人的对象 Customer customer = new Customer(); customer.setCustName("同福客栈"); customer.setCustLevel("vip"); customer.setCustSource("网络"); customer.setCustPhone("110"); customer.setCustMobilb("666"); LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("lucy"); linkMan.setLkm_gender("男"); linkMan.setLkm_phone("911"); //2.在客户里面表示联系人, 在联系人里面表示客户 //建立客户人对象和联系人对象的关系 //2.1 把联系人的对象放到客户实体类对象的set集合里面 customer.getSetLinkMan().add(linkMan); //2.2 把客户对象放到联系人里面 linkMan.setCustomer(customer); //3.保存到数据库 session.save(customer); session.save(linkMan);
简化写法:(根据客户添加联系人)
第一步: 在客户映射文件中进行配置; 在客户映射配置文件中 set标签内进行配置 属性==> cascade="save-update" <set name="setLinkMan" cascade="save-update"> 第二步:创建客户和联系人对象,只要把联系人放到客户里面就可以了,最终只需要保存客户就可以了.
//1.创建客户跟联系人的对象 Customer customer = new Customer(); customer.setCustName("龙门客栈"); customer.setCustLevel("普通客户"); customer.setCustSource("网络"); customer.setCustPhone("949"); customer.setCustMobilb("2233"); LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("小花"); linkMan.setLkm_gender("女"); linkMan.setLkm_phone("666"); //2.把联系人放到客户里面 customer.getSetLinkMan().add(linkMan); //3.保存客户 session.save(customer); session.save(linkMan);
(3).一对多级联删除
(1).删除某一个客户, 这个客户里面的所有联系人也删除 (删除某个客户,把客户里面所有的联系人删除) 第一步:在客户映射文件set标签`,进行配置==> cascade="save-delete" (注意, 多个属性用逗号隔开) (1).使用属性cascade="save-update,delete" 第二步:在代码中直接删除客户. (1).先根据id查询对象,在调用session里面的delete方法删除
//1.根据id查询出客户对象 Customer customer = session.get(Customer.class, 2); //2调用方法删除 session.delete(customer);
执行过程: (1).根据id查询客户 (2).根据外键查询联系人 (3).把联系人的外键设置为null; (4).删除联系人和客户
(4).一对多修改操作
1.让lucy联系人所属客户不是同福, 而是龙门
//1.根据id查询lucy联系人, 根据id查询百度的客户 Customer Tongfu = session.get(Customer.class, 3); LinkMan lucy = session.get(LinkMan.class, 1); //2.设置持久态对象值 //把联系人客户里面 Tongfu.getSetLinkMan().add(lucy); //把客户放到联系人里面 lucy.setCustomer(Tongfu);
(5).inverse属性
1.因为hibernate双向维护外键,在客户和联系人里面都需要维护外键, 修改客户的时候修改一次外键, 修改联系人的时候也修改一次外键, 造成效率问题.2.解决方式: 让其中一的一方不维护外键 一对多里面, 让其中一方放弃对外键的维护. 一个国家有总统, 国家有很多人, 总统不能这个国家所有的人, 国家所有的人认识总统.3.具体实现: 在放弃关系维护映射文件中, 进行配置, 在set标签上使用inverse属性
<!-- inverse属性默认是false不放弃关系维护 true 放弃关系维护 --> <set name="setLinkMan" cascade="save-update,delete" inverse="true">
hibernate 多对多操作:
(1).多对多映射配置
以用户和角色为例演示: 第一步: 创建实体类: 用户和角色 第二步: 两个实体类之间相互表示 (1).用户里面表示所有角色,使用set集合 (2).一个角色多个用户,使用set集合 第三步: 配置映射关系 (1). 基本配置 (2). 配置多对多关系 在用户里面表示所有的角色, set标签
<!-- 在用户里面表示所有角色, 使用set标签 name属性, 角色set集合名称 table属性, 第三张表的名称 --> <set name="setRole" table="user_role"> <!-- key标签里面要配置当前的映射文件在第三张表中外键名称 --> <key column="userid"></key> <!-- class: 角色实体类全路径 column: 角色在第三张表外键名称 --> <many-to-many class="com.yao.entity.Role" column="roleid"></many-to-many> </set>
在角色里面表示所有的用户, set标签
<!-- 在角色里面表示所有的用户, set标签 --> <set name="setUser" table="user_role"> <!-- 角色在第三张表的外键 --> <key column="roleid"></key> <many-to-many class="com.yao.entity.User" column="userid"></many-to-many> </set>
第四步: 在核心配置文件中映入配置文件
<mapping resource="com/yao/entity/User.hbm.xml"/> <mapping resource="com/yao/entity/Role.hbm.xml"/>
第五步: 测试 运行utils类, 查看数据库是否创建三张表.
(2).多对多级联保存(重点)
根据用户保存用户 第一步: 在用户映射配置文件中 set标签进行配置, cascade值 save-update
<set name="setRole" table="user_role" cascade="save-update">
第二步: 写代码实现 (1).创建用户和角色, 把角色放到用户里面, 最终保存用户就可以了.
//添加连个用户, 为没有用户添加两个角色 User user1 = new User(); user1.setUser_name("lucy"); user1.setUser_password("123"); User user2 = new User(); user2.setUser_name("mary"); user2.setUser_password("456"); Role role1 = new Role(); role1.setRole_name("总经理"); role1.setRole_memo("总经理"); Role role2 = new Role(); role2.setRole_name("秘书"); role2.setRole_memo("秘书"); Role role3 = new Role(); role3.setRole_name("保安"); role3.setRole_memo("保安"); //2.建立关系,把角色放到用户里面 //user1 ==> r1/r2 user1.getSetRole().add(role1); user1.getSetRole().add(role2); //user2 ==> r2/r3 user2.getSetRole().add(role2); user2.getSetRole().add(role3); //3.保存用户 session.save(user1); session.save(user2);
(3).多对多级联删除
第一步: 在set标签里面进行配置,cascade 里面 save-update,delete
<set name="setRole" table="user_role" cascade="save-update,delete">
第二步:(注意: 一般不用, 删除会将相关联的表的全部数据删除)
//级联删除 User user = session.get(User.class, 1); session.delete(user);
(4).维护第三张表
1.用户和叫是多对多关系, 维护关系是通过第三张表维护2.让某个用户有某个角色 第一步: 先根据id查询用户和角色 第二步: 把角色对象放到用户里面 (1).把角色对象放到用户set集合
//让lucy有经纪人的角色 //1.查询lucy和经纪人 User lucy = session.get(User.class, 1); Role role = session.get(Role.class, 4); //2.把角色放到用户的set集合里面 lucy.getSetRole().add(role);
3.让某个用户没有某个角色. 第一步: 先根据id查询用户和角色 第二步: 从用户里面把角色去掉 (1).从set集合里面把角色移除
//让lucy有经纪人的角色 //1.查询lucy和经纪人 User lucy = session.get(User.class, 2); Role role = session.get(Role.class, 3); //从用户里面把角色去掉 lucy.getSetRole().remove(role);
hibernate 查询方式:
1.对象导航查询
(1).根据id查询某个客户, 在查询这个客户里面所有联系人.(2).查询某个客户里面所有联系人过程, 使用对象导航实现.
//根据cid=1客户, 在查询这个客户里面所有的联系人 Customer customer = session.get(Customer.class, 1); //在查询这个客户里面所有的联系人 //直接得到客户里面联系人的set集合. Set<LinkMan> linkMan = customer.getSetLinkMan(); System.out.println(linkMan.size());
2.OID 查询
(1).根据id查询某一条记录, 返回对象的形式(2).调用session里面的get方法;
Customer customer = session.get(Customer.class, 1);
3.hql 查询
(1).Query对象, 写hql语句实现查询(2).hql: hibernate query language, hibernate提供的一种语言.hql语言和普通sql相似. 区别: 普通sql操作数据库表和字段, hql操作实体类和属性.(3).常用的hql语句(4).使用hql查询操作时候, 使用query对象. (1).创建Query对象,写hql语句. (2).调用Query对象里面的而方法得到结果.(5)常用查询: 1.查询所有:(重点) (1).创建Query对象,写hql语句(from 实体类的名称) (2).调用query对象里面的方法得到结果.
//创建Query对象 Query query = session.createQuery("from Customer"); //2.调用方法得到结果 List<Customer> list = query.list(); for (Customer customer : list) { System.out.println(customer.getCid() + " , " + customer.getCustName()); }
2.条件查询(重点)
(1).hql条件查询语句的写法: from 实体类名称 where 实体类属性名称=? and 实体类属性名称=?
//1.创建Query对象 Query query = session.createQuery("from Customer where cid=? and custName=?"); //2.设置条件值 //向?里面设置值 //setParameter 方法两个参数 //第一个参数: int类型是?位置, ?位置从0开始. //第二个参数: 具体参数值 //设置第一个?的值 query.setParameter(0, 1); //设置第二个?的值 query.setParameter(1, "同福客栈"); //3.调用方法得到结果 List<Customer> list = query.list(); for (Customer customer : list) { System.out.println(customer.getCid() + " , " + customer.getCustName()); }
1.模糊查询(重点)
(1).hql语句: from 实体类名称 where 属性名称 like ? .
//1.创建Query对象 Query query = session.createQuery("from Customer where custName like ?"); //设置?的值 //_客_ %客 %客% query.setParameter(0,"%客%"); //3.调用方法得到结果 List<Customer> list = query.list(); for (Customer customer : list) { System.out.println(customer.getCid() + " , " + customer.getCustName()); }
2.排序查询 (重点)
(1).hql语句: from 实体类名称 order by 实体类属性名称 desc/asc.
//1.创建Query对象 Query query = session.createQuery("from Customer order by cid desc"); //2.调用方法 List<Customer> list = query.list(); for (Customer customer : list) { System.out.println(customer.getCid() + " , " + customer.getCustName()); }
3.分页查询(重点)
(1)Mysql实现分页 关键字: limit(2).hql中实现分页 1.在hql操作中, 在语句中不能写limit, hibernate 的Query对象封装两个方法实现分页操作.
//1.创建Query对象 Query query = session.createQuery("from Customer"); //2.设置分页的那些数据 //2.1 设置开始位置 query.setFirstResult(0); //2.2 设置每页记录数 query.setMaxResults(3); //3.调用方法得到结果 List<Customer> list = query.list(); for (Customer customer : list) { System.out.println(customer.getCid() + " , " + customer.getCustName()); }
4.投影查询
(1).投影查询: 查询不是所有字段值, 而是部分字段值.(2).投影查询hq语句写法: 1. select 实体类属性名称1,实体类属性名称2 from 实体类名称 2. select 不能写*号, 不支持.
//1.创建Query对象 Query query = session.createQuery("select custName from Customer"); //2.调用方法得到结果 List<Object> list = query.list(); for (Object object : list) { System.out.println(object); }
5.聚合函数使用
(1).常用的聚集函数 1.count(统计个数), sum(相加), avg(平均数), max(最大值), min(最小值)(2).查询表记录数: select count(*) from 实体类名称.
//1.创建Query对象 Query query = session.createQuery("select count(*) from Customer"); //2.调用方法得到结果 //Query对象里面有方法, 直接返回对象形式 Object object = query.uniqueResult(); //System.out.println(object); //返回int类型 有类型转换异常 //int count = (int)object; //首先要把object变成long类型,再转化为int; Long lobj = (Long)object; int count = lobj.intValue(); System.out.println(count);
4.QBC 查询
1.使用hql查询的时候需要写hql语句查询, 而使用QBC查询, 不需要使用语句, 使用方法实现2.使用QBC时候, 操作实体类属性3.使用QBC, 使用Criteria对象实现4.QBC相关查询:
(1).查询所有
1.创建Criteria对象 2.调用方法得到结果
//1.创建对象 Criteria criteria = session.createCriteria(Customer.class); //2.调用方法得到结果 List<Customer> list = criteria.list(); for (Customer customer : list) { System.out.println(customer.getCid() + " , " + customer.getCustName()); }
(2).条件查询
1.没有语句, 使用封装的方法实现.
//1.创建对象 Criteria criteria = session.createCriteria(Customer.class); //2.使用criteria对象里面的方法设置条件值 //首先使用add方法,表示设置属性值 //在add方法里面使用类的方法实现条件设置; //类似与cid=? criteria.add(Restrictions.eq("cid", 1)); criteria.add(Restrictions.eq("custName", "同福客栈")); //3.调用方法得到结果 List<Customer> list = criteria.list(); for (Customer customer : list) { System.out.println(customer.getCid() + " , " + customer.getCustName()); }
(3).模糊查询
//1.创建对象 Criteria criteria = session.createCriteria(Customer.class); //2.使用criteria对象里面的方法设置条件值 //首先使用add方法,表示设置属性值 //在add方法里面使用类的方法实现条件设置; //类似与cid=? criteria.add(Restrictions.like("custName", "%客栈%")); //3.调用方法得到结果 List<Customer> list = criteria.list(); for (Customer customer : list) { System.out.println(customer.getCid() + " , " + customer.getCustName()); }
(4).分页查询
开始位置计算公式: 当前页 - 1 * 每页记录数
//1.创建对象 Criteria criteria = session.createCriteria(Customer.class); //2.设置分页的数据 //2.1 设置开始位置 criteria.setFirstResult(0); //2.2 设置显示记录数 criteria.setMaxResults(3); //3.调用方法得到结果 List<Customer> list = criteria.list(); for (Customer customer : list) { System.out.println(customer.getCid() + " , " + customer.getCustName()); }
(5).统计查询
//1.创建对象 Criteria criteria = session.createCriteria(Customer.class); //2.设置操作 criteria.setProjection(Projections.rowCount()); //3.调用方法得到结果 Object obj = criteria.uniqueResult(); Long lobj = (Long)obj; int count = lobj.intValue(); System.out.println(count);
(6).离线查询
1.servlet调用service. service调用dao (1).在到里面对数据库crud操作 (2).在到里面使用hibernate框架, 使用hibernate框架时候, 调用session里面的方法实现功能.
//1.创建对象 //Criteria criteria = session.createCriteria(Customer.class); DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class); //2.最终执行的时候才需要到session Criteria criteria = detachedCriteria.getExecutableCriteria(session); List<Customer> list = criteria.list(); for (Customer customer : list) { System.out.println(customer); }
HQL多表查询:
Mysql里面多表查询
1.内连接查询 select * from t_customer c,t_linkman l where c.cid=l.clid; select * from t_customer c inner join t_linkman l on c.cid=l.clid; 2.左外连接 select * from t_customer c left outer join t_linkman l on c.cid=l.clid; 3.右外连接 select * from t_customer c right outer join t_linkman l on c.cid=l.clid;
HQL实现多表查询
HQL多表查询
(1).内连接
1.内连接查询hql语句写法:(以客户和联系人为例) (1).from Customer c inner join c.setLinkMan
//1.创建Query对象 Query query = session.createQuery("from Customer c inner join c.setLinkMan"); List list = query.list(); //返回list, list里面每部分是数组形式.
(2).左外连接
(1)hql语句:from Customer c left outer join c.setLinkMan; (2).左外连接返回list每部分都是数组的形式, 迫切左外连接则是对象形式.
//1.创建Query对象 Query query = session.createQuery("from Customer c left outer join c.setLinkMan"); List list = query.list();
(3).右外连接
(1)hql语句: from Customer c right outer join c.setLinkMan; (2).返回结果还是数组形式, 且没有迫切右外连接
//1.创建Query对象 Query query = session.createQuery("from Customer c right outer join c.setLinkMan"); List list = query.list();
(4).迫切内连接
(1).迫切内连接和内连接底层实现一样的(2).区别: 使用普通的内连接返回的list中每部分是数组, 迫切内连接返回list每部分是对象(3).hql语句:from Customer c inner join fetch c.setLinkMan;
//1.创建Query对象 Query query = session.createQuery("from Customer c inner join fetch c.setLinkMan"); List list = query.list();
(5).迫切左外连接
(1).from Customer c left outer join fetch c.setLinkMan;
//1.创建Query对象 Query query = session.createQuery("from Customer c left outer join fetch c.setLinkMan"); List list = query.list();
hibernate 检索策略
1.检索策略的概念:
(1)立即检索/立即查询
根据id查询,调用get方法, 一调用get方法就马上发送查询语句查询数据库.
//根据cid=1客户 //get方法执行之后, 是否发送sql语句. //调用get方法马上发送sql语句查询数据库 Customer customer = session.get(Customer.class, 1); System.out.println(customer.getCid());
(2)延迟查询
根据id查询,还有load方法, 不会马上发送语句查询数据库, 只有得到对象里面的值的时候才会去发送语句查询数据库.
//根据cid=1客户 /* 1.调用load方法之后, 不会马上发送sql语句 (1). 返回对象里面只有id值 2.得到对象里面不是id的其他值的时候才会发送sql语句. */ Customer load = session.load(Customer.class, 1); System.out.println(load.getCid()); System.out.println(load.getCustName());
2.延迟查询中有分为两类
(1).类级别延迟
根据id查询返回实体类对象, 调用load方法不会马上发送sql语句
//根据cid=1客户 /* 1.调用load方法之后, 不会马上发送sql语句 (1). 返回对象里面只有id值 2.得到对象里面不是id的其他值的时候才会发送sql语句. */ Customer load = session.load(Customer.class, 1); System.out.println(load.getCid()); System.out.println(load.getCustName());
(2).关联级别的延迟
查询某个客户, 在查询这个客户所有联系人, 查询客户的所有联系人的过程是否需要延迟, 这个过程称为关联级别延迟.
3.关联基本延迟操作:
1.在映射文件中进行配置实现
(1).根据客户得到所有联系人, 在客户映射文件中配置
2.在set标签上使用两个属性:
(1)fetch 值 select(默认)(2)lazy : 值 - true : 延迟(默认) - false : 不延迟 1.调用get方法后, 直接执行两条查询语句. - extra : 及其延迟/及其懒惰 1.要什么值给什么值, 不要不给
批量抓取:
1.查询所有的客户, 返回list集合, 遍历这个list集合, 得到每个客户, 得到每个客户的所有联系人.
//查询所有的客户 Criteria criteria = session.createCriteria(Customer.class); List<Customer> list = criteria.list(); //得到所有客户里面所有的联系人 for (Customer customer : list) { System.out.println(customer.getCid() + " , " + customer.getCustName()); Set<LinkMan> setLinkMan = customer.getSetLinkMan(); for (LinkMan linkMan : setLinkMan) { System.out.println(linkMan.getLkm_id() + " , " + linkMan.getLkm_name()); } } //上面代码发送多条sql语句, 效率极地
批量抓取代码:
1.在客户的set表里里面 batch-size
<set name="setLinkMan" cascade="save-update,delete" inverse="true" batch-size="10">
里面的值, 越大执行越快, 减少语句发送
//查询所有的客户 Criteria criteria = session.createCriteria(Customer.class); List<Customer> list = criteria.list(); //得到所有客户里面所有的联系人 for (Customer customer : list) { System.out.println(customer.getCid() + " , " + customer.getCustName()); Set<LinkMan> setLinkMan = customer.getSetLinkMan(); for (LinkMan linkMan : setLinkMan) { System.out.println(linkMan.getLkm_id() + " , " + linkMan.getLkm_name()); } }
Hibernate框架的搭建:
1.导包
1.1 : Hibernate核心包(hibernate-release-5.0.7.Final.zip ==> lib ==> required(必须的意思) ==> 里面所有的包) 1.2 : Hibernate驱动包(是Mysql就用mysql的包 , 是oracle就用oracle的包)
2.创建数据库,准备表
cst_customer(表名)
3.书写ORM元数据(对象与表的映射配置文件; "元数据"理解为ORM的"映射文件")
3.1 : 导入约束.(Liberaries ==> Web App Liberaries ==> hibernate-core-5.0.7.Final.jar ==> org.hilbernate ==> hilbernate-configuration-3.0(4.0).xsd ) Window ==> preferences ==> XML ==> XML Catalog ==> Add ==> File System ==> (将dtd文件选中, 自己的 hibernate-configuration-3.0.dtd 文件) ==> Key type选择URL ==> Key的路径是hilbernate-configuration-3.0(4.0).xsd 这个文件注释中的路径 http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd 3.2 : (进入)实体类编写 3.3 : 书写ORM元数据 (看Customer.hbm.xml的配置信息) hibernate-release-5.0.7.Final.zip ==> project ==> etc(下面放的配置文件) ==> hiberbate.properties 里面全部都是要用到的信息(在里面找到Mysql 或 Oracle 的配置)
4. 书写主配置文件
连接数据库的相关配置信息(文件名必须(框架名.config.xml)hibernate.cfg.xml)
5. 书写代码测试
例:
类名.hbm.xml
<!-- 这个头不建议手写, 建议coby --> <?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"> <!-- 头到这结束 --> <!-- 配置与实体对象的关系 (配置文件的根元素); package 指包名, 填写包名 ; 必须先配置package属性,在元素内部凡是需要书写完整的类名的属性, 可以直接写简单的类名--> <hibernate-mapping package="com.yao.www.bean"> <!-- class中要带有两个行内属性, name 和table --> <!-- calss元素: 配置 实体与表的对应关系的 name : 完整类名 table : 数据库表名 --> <class name="完整的实体类的名字路径" table="数据库中表的名字"> <!-- id中要带有两个行内属性, name 和 column(是对应数据库中的某个列) --> <!-- id:用来配置主键映射的属性 ; name属性填写主键对应属性名 ; column填写表中主键的列名--> <id name="实体类中的属性名id" column="与实体类中的属性名对应的数据库中的列名id"> <!-- generator : 主键生成策略(后面详述) --> <generator class="notive"></generator> </id> <!-- property中 ,要添加column属性--> <!-- property的数量与数据库中列的数量一致 --> <!-- property : 用来配置除了id之外的属性的映射 ; name属性填写对应属性名 ; column(可选)填写表中列名 默认值是列名会使用属性名; type(可选,hibernate会自动检测实体的类型, 要写可以三种类型 : java类型 : 例: java.long.String hibernate类型 : 例: string sql类型 : 例 : <property name="" colum="id"> <colum name="id" sql-type="varchar"></colum> </property> not_null :(可选) 配置该属性的列是否不能为空;(默认是false) length :(可选) 配置数据库列的长度, 默认值是(当前数据库类型的最大长度255) 是填写列(属性)的类型 (上面id里面也可以写这些属性) --> <property name="name" column="name" type=""></property> <property name="age" column="age"></property> </class> </hibernate-mapping>
配置文件详解:
分为三部分:
1.ORM元数据
2.hibernate主配置
必选属性(5个)
1.驱动 ==> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> 2.数据库连接驱动(/// 代表localhost(本机) , 后面写数据库名称) ==> <property name="hibernate.connection.url">jdbc:mysql:///数据库名称</property> 3.数据库账号 ==> <property name="hibernate.connection.username">root</property> 4.数据库密码 ==> <property name="hibernate.connection.password">root</property>
可选属性(3个)
sql语句打印到控制台: <property name="hibernate.show_sql">true</property> sql语句的格式格式化(缩进): <property name="hibernate.format_sql">true</property> 创建新表的时的操作: <property name="hibernate.hbm2ddl.auto">update</property>
元数据的引入配置
<!-- 引入orm的元数据 ; 路径书写规范 : 填写Src下的路径 --> <mapping resource="com/yao/www/bean.hbm.xml"/>
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框架 --> <<hibernate-configuration> <session-factory> <!-- #hibernate.dialect org.hibernate.dialect.MySQLDialect #hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect #hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect #hibernate.connection.driver_class org.gjt.mm.mysql.Driver #hibernate.connection.driver_class com.mysql.jdbc.Driver #hibernate.connection.url jdbc:mysql:///test #hibernate.connection.username gavin #hibernate.connection.password --> <!-- 必选配置 --> <!-- 数据库驱动 --> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <!-- 数据库url ; /// 代表localhost(本机) , 后面写数据库名称--> <property name="hibernate.connection.url">jdbc:mysql:///数据库名称</property> <!-- 数据库账号 --> <property name="hibernate.connection.username">root</property> <!-- 数据库密码 --> <property name="hibernate.connection.password">root</property> <!-- 数据库方言 例: Mysql的分页limit 就是Mysql的方言; 不同的数据库中sql语句略有区别, 指定方言可以让Hibernate框架在生成sql语句时, 针对数据库的方言生成. sql99标准: DDL(数据定义语言) 库表的增删改查 DCL(数据控制语言) 事物权限 DML(数据操纵语言)增删改查 TCL(事务控制语言)(X) 注意事项: MySql在选择方言时, 请选择最短的方言. --> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <!-- 可选配置 --> <!-- #hibernate.show_sql true #hibernate.format_sql true --> <!-- hilbernate 会把生成的sql语句打印到控制台 --> <property name="hibernate.show_sql">true</property> <!-- 把sql语句打印到控制台进行格式化 (缩进), 不格式化就是sql语句就是一条--> <property name="hibernate.format_sql">true</property> <!-- ## auto schema export ==> 自动导出表结构, 自动建表 #hibernate.hbm2ddl.auto create 自动建表,每次框架运行外以后都会创建新的表, 以前的表将会被覆盖.表数据会丢失,一般在开发环境中的测试中使用. #hibernate.hbm2ddl.auto create-drop 自动建表, 并且每次框架运行结束都会将表删除(开发环境测试中). #hibernate.hbm2ddl.auto update(推荐使用) 自动建表, 如果已经存在就不会在创建了, 如果表有变动, 自动更新表.(在正式的项目更新时使用, 自动更新表, 不会删除任何数据) #hibernate.hbm2ddl.auto validate 效验, 不自动生成表, 每次启动效验数据库中表是否正确, 效验失败会抛出异常 --> <property name="hibernate.hbm2ddl.auto">update</property> <!-- 引入orm的元数据 ; 路径书写规范 : 填写Src下的路径 --> <mapping resource="com/yao/www/bean.hbm.xml"/> </session-factory> </hibernate-configuration>
HibernateAPI详解:
Configuration(Dome)
Dome.java:
package com.yao.b_API; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import com.yao.www.bean; /** * * @ClassName: Demo * @Description: 学习Configuration * @author: Administrator * @date: 2018年7月3日 下午6:46:06 * 备注:Configuration 功能: 配置加载类, 用户加载主配置, orm元数据的加载 */ public class Demo { //保存用户 public void fun1(){ //1.创建. 调用一个空參的方法 Configuration conf = new Configuration(); //2. 读取指定的主配置文件 , 空參加载方法是 加载src下的hibernate.cfg.xml 文件 conf.configure(); //3. 读取指定orm元数据(上古时期的方法) , 如果主配置中引入了映射配置就不需要手动加载 //conf.addResource(resourceName); //conf.addClass(persistentClass) //4.根据配置信息, 创建SessionFactory SessionFactory buildSessionFactory = conf.buildSessionFactory(); } }
SessionFactory(Dome2)
如何加载主配置 如何加载orm元数据(上古配置) 获取Session //第一种方法: sf.openSession();//打开一个新的Session对象. //第二种方法: sf.getCurrentSession(); //获得与线程绑定的Session对象
Dome02.java
package com.yao.b_API; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import com.yao.www.bean; /** * * @ClassName: Demo * @Description: 学习SessionFactory 对象 * @author: Administrator * @date: 2018年7月3日 下午6:46:06 * 备注:SessionFactory 功能: 用于创建操作数据库库的核心对象Session对象的工厂 * 简单的说功能就一个 ==> 创建Session对象 * 注意: * 1.SessionFactory负责保存和使用配置信息, 消耗内存资源非常大. * 2.SessionFactory属于线程安全的对象设计. * 结论: * 保证Web项目中, 只创建一个SessionFactory. 因为SessionFactory是一个线程安全的对象, 但是十分消耗资源. */ public class Demo2 { //保存用户 public void fun1(){ //1.创建. 调用一个空參的方法 Configuration conf = new Configuration(); //2. 读取指定的主配置文件 , 空參加载方法是 加载src下的hibernate.cfg.xml 文件 conf.configure(); //3. 读取指定orm元数据(上古时期的方法) , 如果主配置中引入了映射配置就不需要手动加载 //conf.addResource(resourceName); //conf.addClass(persistentClass) //4.根据配置信息, 创建SessionFactory SessionFactory sf = conf.buildSessionFactory(); //============================================> //5.获取Session //第一种方法: sf.openSession();//打开一个新的Session对象. //第二种方法: sf.getCurrentSession(); //获得与线程绑定的Session对象 } }
Session(Dome3)
Dome3.java
package com.yao.b_API; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; import com.yao.www.bean; /** * * @ClassName: Demo * @Description: 学习Session 对象 * @author: Administrator * @date: 2018年7月3日 下午6:46:06 * 备注:Session 功能: 表达Hibernate框架与数据库之间的连接(会话).Session类似于JDBC年代connection对象.还可以完成对数据库中的增删改查 * Sessions是hibernate操作的核心对象 * */ public class Demo3 { @Test //事务操作 public void fun1(){ //1.创建. 调用一个空參的方法 Configuration conf = new Configuration().configure(); //2.根据配置信息, 创建SessionFactory SessionFactory sf = conf.buildSessionFactory(); //============================================> //3.获取Session //第一种方法: Session session = sf.openSession();//打开一个新的Session对象. //第二种方法: //sf.getCurrentSession(); //获得与线程绑定的Session对象 //4.session获得操作事物的Transaction对象 //第一种 //获得操作事物的tx对象 //Transaction tx = session.getTransaction(); //第二种: //开启事物并获得操作事物的tx对象(推荐使用) Transaction tx2 = session.beginTransaction(); //========================================== //========================================== tx2.commit();// 提交事物 tx2.rollback();//回滚事物 session.close();//释放资源 sf.close();//释放资源 } @Test //session的新增功能 public void fun2(){ //1.创建. 调用一个空參的方法 Configuration conf = new Configuration().configure(); //2.根据配置信息, 创建SessionFactory SessionFactory sf = conf.buildSessionFactory(); //============================================> //3.获取Session //第一种方法: Session session = sf.openSession();//打开一个新的Session对象. //第二种方法: //sf.getCurrentSession(); //获得与线程绑定的Session对象 //4.session获得操作事物的Transaction对象 //第一种 //获得操作事物的tx对象 //Transaction tx = session.getTransaction(); //第二种: //开启事物并获得操作事物的tx对象(推荐使用) Transaction tx2 = session.beginTransaction(); //========================================== bean bean = new bean();//创建实体类的对象 bean.setName("小花"); //使用实体类对象中的set方法 给其属性赋值 session.save(bean); //将bean放入到Session对象中 //========================================== tx2.commit();// 提交事物 //tx2.rollback();//回滚事物 session.close();//释放资源 sf.close();//释放资源 } @Test //session的查询功能 //以id 来查询 public void fun3(){ //1.创建. 调用一个空參的方法 Configuration conf = new Configuration().configure(); //2.根据配置信息, 创建SessionFactory SessionFactory sf = conf.buildSessionFactory(); //============================================> //3.获取Session //第一种方法: Session session = sf.openSession();//打开一个新的Session对象. //第二种方法: //sf.getCurrentSession(); //获得与线程绑定的Session对象 //4.session获得操作事物的Transaction对象 //第一种 //获得操作事物的tx对象 //Transaction tx = session.getTransaction(); //第二种: //开启事物并获得操作事物的tx对象(推荐使用) Transaction tx2 = session.beginTransaction(); //========================================== //第一个参数是写找哪一个类型 ,第二个参数写要查询的那个值.(id后面要加一个L, 因为id的类型为long型) bean bean = session.get(bean.class, 1L); System.out.println("bean = " + bean); //========================================== tx2.commit();// 提交事物 //tx2.rollback();//回滚事物 session.close();//释放资源 sf.close();//释放资源 } @Test //session的修改功能 //修改以id为准的属性 public void fun4(){ //1.创建. 调用一个空參的方法 Configuration conf = new Configuration().configure(); //2.根据配置信息, 创建SessionFactory SessionFactory sf = conf.buildSessionFactory(); //============================================> //3.获取Session //第一种方法: Session session = sf.openSession();//打开一个新的Session对象. //第二种方法: //sf.getCurrentSession(); //获得与线程绑定的Session对象 //4.session获得操作事物的Transaction对象 //第一种 //获得操作事物的tx对象 //Transaction tx = session.getTransaction(); //第二种: //开启事物并获得操作事物的tx对象(推荐使用) Transaction tx2 = session.beginTransaction(); //========================================== //第一步 : 要获得要修改的对象 bean b = session.get(bean.class, 1L); //第二步 : 修改 b.setName("咸鱼干"); //第三步 : 执行update session.update(b); //========================================== tx2.commit();// 提交事物 //tx2.rollback();//回滚事物 session.close();//释放资源 sf.close();//释放资源 } @Test //session的删除功能 //删除以id为准的属性 public void fun5(){ //1.创建. 调用一个空參的方法 Configuration conf = new Configuration().configure(); //2.根据配置信息, 创建SessionFactory SessionFactory sf = conf.buildSessionFactory(); //============================================> //3.获取Session //第一种方法: Session session = sf.openSession();//打开一个新的Session对象. //第二种方法: //sf.getCurrentSession(); //获得与线程绑定的Session对象 //4.session获得操作事物的Transaction对象 //第一种 //获得操作事物的tx对象 //Transaction tx = session.getTransaction(); //第二种: //开启事物并获得操作事物的tx对象(推荐使用) Transaction tx2 = session.beginTransaction(); //========================================== //第一步: 查询 bean b = session.get(bean.class, 1L); //第二步: 调用delete方法删除 session.delete(b); //========================================== tx2.commit();// 提交事物 //tx2.rollback();//回滚事物 session.close();//释放资源 sf.close();//释放资源 } }
Transaction
控制事务
hibernateUtils(工具类的封装)
package com.yao.dbutils; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.loader.custom.Return; import com.yao.www.bean; /** * * @ClassName: HibernateUtils * @Description: 工具类 * @author: Administrator * @date: 2018年7月3日 下午10:03:04 */ public class HibernateUtils { private static SessionFactory sf; static{ //1.创建. 调用一个空參的方法 Configuration conf = new Configuration().configure(); //2.根据配置信息, 创建SessionFactory sf = conf.buildSessionFactory(); } //获得Session的方法: ==> 获得一个全新的Session public static Session openSession(){ //3.获取Session Session session = sf.openSession();//打开一个新的Session对象. return session; } //获得Session的方法: ==> 获得一个于线程绑定的Session public static Session getCurrentSession(){ //3.获取Session Session session = sf.getCurrentSession(); return session; } }
测试类
package com.yao.test; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import com.yao.www.bean; /** * * @ClassName: Demo * @Description: 测试 * @author: Administrator * @date: 2018年7月3日 下午6:10:59 */ public class Demo { public void fun1(){ //保存用户 Configuration conf = new Configuration().configure(); SessionFactory sessionFactory = conf.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); //======================================== bean b = new bean(); b.setName("aa"); session.save(b); //======================================== tx.commit(); session.close(); sessionFactory.close(); } }
例:
com.yao.domain.Customer.java
package com.yao.domain; public class Customer { /** * CREATE TABLE `cst_customer` ( `cust_id` bigint(20) NOT NULL AUTO_INCREMENT, `cust_name` varchar(255) DEFAULT NULL, `cust_source` varchar(255) DEFAULT NULL, `cust_industry` varchar(255) DEFAULT NULL, `cust_level` varchar(255) DEFAULT NULL, `cust_linkman` varchar(255) DEFAULT NULL, `cust_phone` varchar(255) DEFAULT NULL, `cust_moblie` varchar(255) DEFAULT NULL, `cust_mobile` varchar(255) DEFAULT NULL, PRIMARY KEY (`cust_id`) ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=gbk; */ private Long cust_id; private String cust_name; private String cust_source; private String cust_industry; private String cust_level; private String cust_linkman; private String cust_phone; private String cust_moblie; 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 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_moblie() { return cust_moblie; } public void setCust_moblie(String cust_moblie) { this.cust_moblie = cust_moblie; } @Override public String toString() { return "Customer [cust_id=" + cust_id + ", cust_name=" + cust_name + "]"; } }
com.yao.domain.Cutomer.hbm.xml
<?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"> <!-- 配置表与实体对象的关系--> <!--package属性:填写一个包名 ,在元素内部凡是需要书写完整的类名的属性,可以直接写简单的类名 --> <hibernate-mapping package="com.yao.domain"> <!-- class元素:配置实体与表的对应关系的 name:完整类名 table:数据库表名 --> <class name="Customer" table="cst_customer"> <!-- id元素:配置主键映射的属性 name:填写主键对应属性名 column(可选):填写表中的主键列名 默认值:列名会使用属性名 type(可选):填写列(属性)的类型,hibernate会自动检测实体的属性类型。 每个类型有三种填法:java类型|hibernate类型|数据库类型 not-null(可选):配置该属性(列)是否不能为空.默认值:false length(可选):配置 数据库列的长度.默认值:使用数据库类型的最大长度 --> <id name="cust_id" > <!--generator:主键生成策略,就是每天记录录入时,主键的生成规则.(7个) identity:主键自增。 由数据库来维护主键值,在录入时不需要指定主键. sequence:oracle中的主键生成策略. increment(了解) 主键自增,由hibernatel.来维护,每次插入前会先查询表中id最大值.+1作为新主键值 hilo():高低位算法.主键自增,由hibernatel。开发时不使用. native:hilo+sequence+identity 自动三选一策略. uuid:产生随机字符串作为主键。主键类型必须为String类型. assigned:自然主键生成策略.hibernate不会管理主键值,由开发人员自己录入。 --> <generator class="increment"></generator> </id> <!-- propert元素除id之外的普通属性映射 name:填写属性名 column(可选):填写列名 type(可选):填写列(属性)的类型,hibernate会自动检测实体的属性类型。 每个类型有三种填法:java类型|hibernate类型|数据库类型 not-null(可选):配置该属性(列)是否不能为空.默认值:false length(可选):配置 数据库列的长度.默认值:使用数据库类型的最大长度 --> <property name="cust_name" column="cust_name" > <!-- <column name="cust_name" sql-type="varchar"></column>--> </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_moblie" column="cust_moblie"></property> </class> </hibernate-mapping>
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> <!-- #hibernate.dialect org.hibernate.dialect.MySQLDialect #hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect #hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect #hibernate.connection.driver_class com.mysql.jdbc.Driver #hibernate.connection.url jdbc:mysql:///test #hibernate.connection.username gavin #hibernate.connection.password --> <!-- 数据驱动 --> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <!-- 数据库URL --> <property name="hibernate.connection.url">jdbc:mysql:///1806</property> <!-- 数据库连接用户名--> <property name="hibernate.connection.username">root</property> <!-- 数据库连接密码--> <property name="hibernate.connection.password">root</property> <!-- 数据方言 不同的数据中,sql语句略you8区别,指定方言可以让hiberante框架在生成sql语句时,针对数据库的方言生成. sql99标准:DDL:定义语言 库表的增删该查 DCL:控制语言 事务 权限 DML:操作语言 增删该查 注意事项:mysql在选择方言是,请选择最短的方言.hibernate.dialect org.hibernate.dialect.MySQLDialect --> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <!-- #hibernate.show_sql true #hibernate.format_sql true --> <!-- 将hibernate生成的sql语句打印到控制台 --> <property name="hibernate.show_sql">true</property> <!-- 将hibernate生成的sql语句打印到控制台(格式化) --> <property name="hibernate.format_sql">true</property> <!-- ## auto schema export 自动导出表结构.自动建表 #hibernate.hbm2ddl.auto create 自动建表,每次框架运行都会创建新的表。以前的表将会被覆盖。表数据会丢失.(开发环境中测试使用) #hibernate.hbm2ddl.auto create-drop 自动建表,每次框架运行结束都会将所有表删除.(开发环境中测试使用) #hibernate.hbm2ddl.auto update(推荐使用) 自动生成表.如果已经存在不会在生成。如果表有变动,自动更新表.(自动更新表不会删除任何数据) #hibernate.hbm2ddl.auto validate 校验。不自动生成表.每次启动校验数据库中表是否正确。校验失败. 生成环境(Sit4) --> <property name="hibernate.hbm2ddl.auto">update</property> <!-- 引入orm元数据 路径书写:填写src下的路径 --> <mapping resource="com/yao/domain/Customer.hbm.xml"/> </session-factory> </hibernate-configuration>
com.yao.utils.HibernateUtils.java
package com.yao.utils; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; /** * * @author 注意: 此处如出现错误, 极有可能是eclipse 与 jdk的版本不对应, 建议下载同版本的; * */ public class HibernateUtils { private static SessionFactory sf; static{ //1、创建,调用空参方法 Configuration conf = new Configuration().configure(); //2、根据配置信息,创建SessionFactory对象 sf = conf.buildSessionFactory(); } //获得session => 获得全新session public static Session openSession(){ //3、获得session Session session = sf.openSession(); return session; } //获得session => 获得与线程绑定的session public static Session getCurrentSession(){ //3、获得session Session session = sf.getCurrentSession(); return session; } public static void main(String[] args) { System.out.println(HibernateUtils.openSession()); } }
hibernate中的实体规则
实体类创建的注意事项:
1.持久化类提供无參的无參的构造方法 2.成员变量私有化, 并提供GetSet方法进行访问.需要提供属性(在bean的实体类中没有私有化的属性,而是私有化的成员变量.能被称为属性的是配GetSet方法后的成员变量, 那里才能被称为属性) 3.持久化类中的属性, 应尽量使用包装类型.(持久化是对数据库的增删查改)(包装类型是八大基本类型 int 对应 Integer, Long 对应 long… ==> 开头大写就是包装类型) 从jsk1.5就有自动装箱/拆箱,所以这里给包装类. 4.在持久化类中需要提供oid与数据库中的主键列对象.(数据库中叫id,在hibernate里面叫在oid); 没有主键的字段是不被hibernate使用的表. 5.不要用final修饰class 动态代理: 面向接口的代理"cglib" hibernate使用cglib代理生成对象, 代理对象是继承被代理对象, 如果被final修饰, 将无法生成代理对象
主键类型:
1.自然主键(少见) 表的业务列中, 有业务列符合必须有, 并且不重复的特征时, 该类可以叫做自然主键. 2.代理主键(常见) 表的业务中, 没有某业务符合,必须有,并且不重复的特征时,创建一个没有业务意义的列作为代理主键.
<!-- id元素:配置主键映射的属性 name:填写主键对应属性名 column(可选):填写表中的主键列名 默认值:列名会使用属性名 type(可选):填写列(属性)的类型,hibernate会自动检测实体的属性类型。 每个类型有三种填法:java类型|hibernate类型|数据库类型 not-null(可选):配置该属性(列)是否不能为空.默认值:false length(可选):配置 数据库列的长度.默认值:使用数据库类型的最大长度 --> <id name="cust_id" > <!-- generator:主键生成策略,就是每条记录录入时,主键的生成规则.(7个) identity:主键自增。 由数据库来维护主键值,在录入时不需要指定主键. sequence(Oracle独有的):oracle中的主键生成策略. increment(了解,不建议使用,有线程安全问题.) 主键自增,由hibernate来维护,每次插入前会先查询表中id最大值.+1作为新主键值 hilo(数据库中就是使用的高低位算法):高低位算法.主键自增,由hibernate。开发时不使用.==> 与数据库的功能重复了. native(三合一):hilo+sequence+identity 自动三选一策略. uuid:产生随机字符串作为主键。主键类型必须为String类型. assigned:自然主键生成策略.hibernate不会管理主键值,由开发人员自己录入。 --> <generator class="native"></generator> </id>
package com.yao.test.a_generator; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; import com.yao.domain.Customer; import com.yao.utils.HibernateUtils; public class Dome { @Test public void fun1(){ //1.获取Session Session session = HibernateUtils.openSession(); //2.控制事物 Transaction tx = session.beginTransaction(); //3.执行操作 Customer c = new Customer(); c.setCust_name("小明"); session.save(c); //4.提交事物,关闭事物 tx.commit(); session.close(); /* 使用"identity": 控制台打印: Hibernate: insert into cst_customer (cust_name, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_moblie) values (?, ?, ?, ?, ?, ?, ?) */ /* 使用"increment": 控制台打印 Hibernate: select max(cust_id) from cst_customer Hibernate: insert into cst_customer (cust_name, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_moblie, cust_id) values (?, ?, ?, ?, ?, ?, ?, ?) */ } }
hibernate中的对象状态:
对象分为三种状态: 1.瞬时状态 没有id, 没有与session关联, 2.持久化状态 有id, 与session有关联 3.游离状态(托管状态) 有id, 没有与session关联
package com.yao.test.b_state; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; import com.yao.domain.Customer; import com.yao.utils.HibernateUtils; /** * * @author 测试对象的三种状态 * 1.学习对象三种状态结论: * 将我们希望同步到数据库的数据,对应的对象转化为持久化状态. * * */ public class Demo { @Test /** * 查看三种状态 */ public void fun1(){ //1.获取session对应 Session session = HibernateUtils.openSession(); //2.控制事物 Transaction tx = session.beginTransaction(); //3.执行操作 Customer c = new Customer(); //创建出来没有id, 在没有与session关联的时候,属于瞬时状态 c.setCust_name("花花"); //没有id, 没有与session关联, 瞬时状态; session.save(c); //有id, 与session关联, 持久化状态; //4.提交事物,关闭事物 tx.commit(); session.close();// 有id, 与session的关联被关闭, 游离状态/托管状态 } @Test /** * 三种状态的特点(与主键类型有关联) * save方法: 其实不能理解成保存, 应理解为将瞬时状态转化为持久化状态; * 主键自增, 执行save方法, 为了将对象转换为持久化状态, 必须生成id值, 所以需要执行insert语句. * 主键生成策略increment方法: 执行了save方法, 为了生成id, 会执行查询id最大值的sql语句 */ public void fun2(){ //获取session 对象 Session session = HibernateUtils.openSession(); //控制事物 Transaction tx = session.beginTransaction(); //获取实体类 ,并操作实体类 Customer c2 = new Customer(); c2.setCust_name("小米"); //将实体类存放到session对象中 session.save(c2);// save 可以看作对象的瞬时状态转化为持久化状态. //提交事物 tx.commit(); //关闭事物 session.close(); } @Test /** * 三种状态的特点: * 持久化状态的特点: * 持久化状态对象的任何变化都会同步到数据库中. */ public void fun3(){ //获取session对象 Session session = HibernateUtils.openSession(); //获取事物 Transaction tx = session.beginTransaction(); //执行事物 Customer c3 = session.get(Customer.class, 1L); //有id ,与session相关联, 持久化状态对象; c3.setCust_name("hello"); //提交事物 tx.commit(); //关闭事物 session.close(); /* 控制台打印: Hibernate: select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_name as cust_nam2_0_0_, customer0_.cust_source as cust_sou3_0_0_, customer0_.cust_industry as cust_ind4_0_0_, customer0_.cust_level as cust_lev5_0_0_, customer0_.cust_linkman as cust_lin6_0_0_, customer0_.cust_phone as cust_pho7_0_0_, customer0_.cust_moblie as cust_mob8_0_0_ from cst_customer customer0_ where customer0_.cust_id=? Hibernate: update cst_customer set cust_name=?, cust_source=?, cust_industry=?, cust_level=?, cust_linkman=?, cust_phone=?, cust_moblie=? where cust_id=? */ } }
叨叨几句... NOTHING