Hibernate

hibernate是一种ORM框架,解决了对象和表的关系映射,能自动生成sql语句,封装了对数据库的访问。一种面向对象的操作。
Mybatis是面向数据库操作,通过sql和entity的映射,轻量简单。头文件在hibernate的jar包中的dtd文件。
 一.开发步骤(w我们这里使用maven工程,具体如何创建看我的博客)
#导包 hibernate的相关包
<dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.4.4.Final</version>
        </dependency>
 
 
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
 
 
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
        </dependency>
 
 
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>    
            <groupId>org.projectlombok</groupId>    
            <artifactId>lombok</artifactId>    
            <version>1.16.10</version>
        </dependency>
    </dependencies>
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.xml</include>
                    <include>**/*.properties</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>
#添加hibernate的配置文件(数据库的连接、框架参数、映射文件的地址配置 hibernate.cfg.xml)和  映射文件(实体类和表的映射  类.hbm.xml,放于实体类相同的地方)
 
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- 数据库参数 -->
        <property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/test?serverTimezone=UTC</property>
        <property name="connection.username">root</property>
        <property name="connection.password">123456</property>
        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>
        <!-- SQL dialect ,定义数据库方言-->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <!-- session绑定在当前线程 -->
        <property name="current_session_context_class">thread</property>
        <property name="hbm2ddl.auto">update</property>
         <!-- 显示hibernate自动生成的sql语句在控制台 -->
        <property name="show_sql">true</property>
 
 
        <!-- 是否将打印的SQL格式化 -->
        <property name="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>
 
 
         <!-- 指定hibernate操作数据库时的隔离级别
            #hibernate.connection.isolation 1|2|4|8
            0001    1    读未提交
            0010    2    读已提交
            0100    4    可重复读
            1000    8    串行化
         -->
         <property name="hibernate.connection.isolation">4</property>
 
 
         <!-- 指定session与当前线程绑定 -->
         <property name="hibernate.current_session_context_class">thread</property>
        <!-- 配置映射文件地址,可以写多个,一般放在实体类一起的 -->
        <mapping resource="com/zy/entity/Product.hbm.xml" />
    </session-factory>
</hibernate-configuration>
 
#定义实体类,这里使用lombok
 
@Data
public class Product {
    int id;
    String name;
    float price;
}
#写实体类和数据库的映射,在实体类Product的同包下新建Product.hbm.xml,这里注意maven的编译不会把src/main/java下的文件编译到classes中,所以在maven的pom.xml中定义resource把那些文件放在classes中,这里也可以把Product.hbm.xml放在src/resources下,那就不需要写这个build,maven会自动把resources的文件放进去。
 
  <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.xml</include>
                    <include>**/*.properties</include>
                </includes>
            </resource>
        </resources>
    </build>
 
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--指定映射关系-->
<hibernate-mapping package="com.zy.entity">
    <class name="Product" table="product_">
        <id name="id" column="id">
            <generator class="native">
            </generator>
        </id>
        <property name="name" />
        <property name="price" />
    </class>
</hibernate-mapping>
 
 
#利用hibernate提供的api访问数据库,运行main函数
 
public class Test {
    public static void main(String[] args) {
        SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
        Session session = sessionFactory.openSession();
        session.beginTransaction();
        Product product = new Product();
        product.setName("周杨");
        product.setPrice(100);
        session.save(product);
//通过id获取数据
System.out.println(session.get(Product.class,3).toString());
        session.close();
        sessionFactory.close();
    }
}
sessionFactory是线程安全的,重量级的,一个数据源最好使用一个实例,所以用util创建它,它是二级缓存,默认关闭的。
session是一级缓存,非线程安全,的创建有两种方式:sessionFactory.openSession(),sessionFactory.getCurrentSession(),后者吧session绑定当前线程,前者需要手动close,后者当食物提交或者异常后自动关闭session。
 
二.Hibernate基础语法
1.增删改查
 
    根据ID查询
    session.get(Emp.class, 1)   查询到不存在的数据,返回null  get方法直接返回实体类对象,
    session.load(Emp.class, 1)   延迟加载,查询到不存在的数据,抛出异常。load方法返回实体类对象的代理
 
     增删改   
session.save(e);
        session.update(e);
 
        session.delete(e);
 
session的save(O)方法会根据映射文件生成insert语句,把数据插入数据库,而且还会把自动生成的主键值读取到这个对象中。
 
 
4.使用标准的sql查询
 
//编写sql语句
        String sql="select * from t_employee where emp_name like ?";
        //根据sql语句创建SQLQuery对象
        SQLQuery sqlQuery = session.createSQLQuery(sql);
        //为占位符设置值
        sqlQuery.setString(0, "%"+name+"%");
        //获取结果集
        List<Object[]> list = sqlQuery.list();
 
  1. HQL查询(和sql类似,和数据库无关)https://how2j.cn/k/hibernate/hibernate-hql/37.html

 from 类名    where 属性   select...  group by..  order by...等
 5.1基础查询
 5.2 排序
5.3 条件
 5.4 分页
5.5 聚合
 5.6 投影
 5.7 连接查询
    5.7.1  内连接 
     5.7.2  fetch的内连接
     5.7.3     左外连接
     5.7.4   右外连接
基本语法:
条件查询:
分页查询:
排序:
聚合:
7.1离线查询
DetachedCriteria,HQL或Criteria都是通过session创建的,离线查询可以不通过session,在ssh开发中可以在web层中封装数据,然后在吧封装好的数据再交给dao层处理。
 
3.ID生成方式(1.1到1.3是数据库自增类型,1.4数据库没设置自增)
1.1 sequence: 根据序列生成ID,用于oracle

<generator class="sequence">

    <param name="sequence">序列名</param>

</generator>

1.2 identity: 自动生成ID,用于其他数据库
        <generator class="identity"></generator>
1.3 native: sequence和identity二选一
        <generator class="native">
    <param name="sequence">序列名</param>
 
        </generator>
1.4 UUID: 按照uuid算法自动生成ID,主键是string类型
        <generator class="uuid"></generator>
 
  1. 实体类对象在Hibernate中有3种状态 ,状态转换

6.1每种状态的特征

瞬时 指的是没有和hibernate发生任何关系,在数据库中也没有对应的记录,一旦JVM结束,这个对象也就消失了 
持久 指得是一个对象和hibernate发生联系,有对应的session,并且在数据库中有对应的一条记录 
脱管 指的是一个对象虽然在数据库中有对应的一条记录,但是它所对应的session已经关闭了 
 
补充:这些session的方法,evict()是从session缓存中驱逐对象,clear()是清空session缓存。
游离态调用delete()会变成临时态,而且会删除数据库中的数据
   6.2 事务管理一般在service层,为了保证service和dao层使用的同一个session,<property name="hibernate.current_session_context_class">thread</property>把session绑定本地线程,当线程结束,session结束。
  1. 关联映射
在数据库中表和表有关系,在实体类上就是引用关系,实体类中的集合一般实例化,防止空指针,关联映射有一对多、多对一、多对多、一对一等等
Product类和Category是多对一关系,就是一个category对应多个product。
7.7.1 多对一映射:
    数据库新建category_表,并且在product_表中增加cid字段作为前表的外键字段。
 
CREATE TABLE `product_` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) DEFAULT NULL,
  `price` float DEFAULT NULL,
  `cid` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `categoryid` (`cid`),
  CONSTRAINT `categoryid` FOREIGN KEY (`cid`) REFERENCES `category_` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
CREATE TABLE `product_` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) DEFAULT NULL,
  `price` float DEFAULT NULL,
  `cid` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `categoryid` (`cid`),
  CONSTRAINT `categoryid` FOREIGN KEY (`cid`) REFERENCES `category_` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
#在Product类中新家Category属性,private Category category,新建Category类
 
@Data
public class Category {
    private String id;
    private String name;
}
 
#在Category同包下添加映射配置文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.how2java.pojo">
    <class name="Category" table="category_">
        <id name="id" column="id">
            <generator class="native">
            </generator>
        </id>
        <property column="name" name="name" />
    </class>
     
</hibernate-mapping>
#在hibernate.cfg.xml中添加category的配置文件
 
<mapping resource="com/zy/entity/Category.hbm.xml" />
 
在Hibernate.hbm.xml配置文件中使用many-to-one 标签设置多对一关系
name="category" 对应Product类中的category属性
class="Category" 表示对应Category类
column="cid" 表示指向 category_表的外键
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.how2java.pojo">
    <class name="Product" table="product_">
        <id name="id" column="id">
            <generator class="native">
            </generator>
        </id>
       <property column="name" name="name" />
<property column="price" name="price" />
        <many-to-one name="category" class="Category" column="cid" />
    </class>
     
</hibernate-mapping>
双击选中所有代码
 
步骤 8 : 在hibernate.cfg.xml中增加Category
 
#测试
 
 
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
System.out.println(session.get(Product.class,3).toString());
session.close();
sessionFactory.close();
可以看到查询product的时候把category查询出来了
 
2.配置一对多关系
#步骤,在category类中新增product属性
 
private List<Product> products;
 
    # 在category.hbm.xml的映射配置文件中配置
<!-- 一对多关联映射配置 -->
 <!-- 指定books属性是list集合,name是属性名 ,取消了延迟加载,采用join抓取策略,这个fetch会使延迟加载失效-->
 
       <set 用于设置一对多(多对多也是他)关系,也可以用list,设置稍复杂点,这里使用简单的set来入门。
name="products" 对应 Category类中的products属性
lazy="false" 表示不使用延迟加载。关于延迟加载,请参考关系的延迟加载
<key column="cid" not-null="false" /> 表示外键是cid,可以为空
<one-to-many class="Product" /> 表示一对多所对应的类是Product
 
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
 
 
<hibernate-mapping package="com.zy.entity">
    <class name="Category" table="category_">
        <id name="id" column="id">
            <generator class="native">
            </generator>
        </id>
        <property column="name" name="name" />
        <set name="products" lazy="false" >
        <key column="cid" not-null="false" />
        <one-to-many class="Product" />
        </set>
    </class>
 
 
</hibernate-mapping>
         测试
 
#
多对多映射
多表对多表,有一个中间表,维护双方的外键,其他一样,就配置不同,set中是many-to-many
<property column="name" name="name" />
        <set name="products" lazy="false" >
        <key column="cid" not-null="false" />
        <many-to-many class="Product" />
        </set>
 
 
 
关系维护:
在保存时.两方都会维护外键关系.关系维护两次,冗余了. 多余的维护关系语句,显然是客户这一端在维护关系
 
 
inverse:
cascade:
以上的关系是双方共同维护,而且操作是两方都save,下面就是定义inverse和cascade操作:
关联标签中的其他属性:
i   inverse 是指的关联关系的控制方向,指外键的维护权,inverse=false 的 side(side 其实是指 inverse=false 所位 于的 class 元素)端有责任维护关系,hibernate默认的双方都是false,而 inverse=true 端无须维护这些关系,建 议交给多的一方维护关系。
 
7.3对session中的缓存对象持久态对象操作,当事务提交时,会自动更新到数据库。
 
8。延迟加载(默认true) 类延迟(class上配置)和关联延迟(set或者many-to-one配置),只有在使用这个类的时候才会查询数据库,比如tescher中有student,查询teacher时不会查到student,当要使用student的时候才会调用select查询
当   需要使用对象的时候才加载数据库的数据到内存对象,使用的是代理机制,Lazy 的有效期:只有在 session 打开的时候才有效;session 关闭后 lazy 就没效了。
例 如上面的user关联book查询,只需要username,hibernate就值加载name,它需要什么信息加加载什么数据。延迟加载在获取需要的数据时是向数据库发送sql请求,所以不能在加载数据前关闭session。
可 关闭延迟加载会带来问题。比如开销很大。
    fetch:抓取策略
      
 
为了解决延迟加载带来的问题,比如获取数据传给表示层,在表示层获取数据的一些属性,但数据库已经关闭,出现问题,可以在表示层使用OpenSessionInView技术,在表示层开启关闭数据库。Servlet中使用过滤器,struts使用拦截器,spring使用aop技术。
9.级联操作, cascade, 什么是级联? 简单的说,没有配置级联的时候,删除分类,其对应的产品不会被删除。 但是如果配置了恰当的级联,那么删除分类的时候,其对应的产品都会被删除掉。
包括上一步说的删除用得级联,级联有4种类型:
all: delete+save-update所有操作都执行级联操作;
none:所有操作都不执行级联操作;
delete:删除时执行级联操作; 
save-update:保存和更新时执行级联操作;
级联通常用在one-many和many-to-many上,几乎不用在many-one上。
用法: <set name="products" cascade="delete" lazy="false">
 
     9.批量加载 batch-size="2" 一对多:获取Teacher时:在set上配置,表示一次加载几个Teacher中的Student集合。 获取Student时:在Teacher的class中配置batch-size="3"。
谈一谈Hibernate的一级缓存、二级缓存和查询缓存。
答:Hibernate的Session提供了一级缓存的功能,默认总是有效的,当应用程序保存持久化实体、修改持久化实体时,Session并不会立即把这种改变提交到数据库,而是缓存在当前的Session中,除非显示调用了Session的flush()方法或通过close()方法关闭Session。通过一级缓存,可以减少程序与数据库的交互,从而提高数据库访问性能。
SessionFactory级别的二级缓存是全局性的,所有的Session可以共享这个二级缓存。不过二级缓存默认是关闭的,需要显示开启并指定需要使用哪种二级缓存实现类(可以使用第三方提供的实现)。一旦开启了二级缓存并设置了需要使用二级缓存的实体类,SessionFactory就会缓存访问过的该实体类的每个对象,除非缓存的数据超出了指定的缓存空间。
一级缓存和二级缓存都是对整个实体进行缓存,不会缓存普通属性,如果希望对普通属性进行缓存,可以使用查询缓存。查询缓存是将HQL或SQL语句以及它们的查询结果作为键值对进行缓存,对于同样的查询可以直接从缓存中获取数据。查询缓存默认也是关闭的,需要显示开启。
hibernate的锁机制:事务隔离 (采用的锁机制) 悲观锁(session或者query设置) 乐观锁 (版本号 实体类 表 然后在xml中配置version版本关系)
使用开启二级缓存:hibernate.cfg.xml中添加
 <property name="hibernate.cache.use_second_level_cache">true</property>
        <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
在src目录下,创建一个ehcache.xml用于EHCache的缓存配置
<ehcache>
    <diskStore path="java.io.tmpdir"/>
    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />
</ehcache>
需要缓存的实体类配置:
<cache usage="read-only" />
 
<hibernate-mapping package="com.how2java.pojo">
    <class name="Category" table="category_">
        <cache usage="read-only" />
 
10.hibernate注解
不用配置文件,使用注解版也可以
@Entity
@Table(name = "product_")
public class Product {
@Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")  
    int id;
@Column(name="name")
    String name;
  
     @ManyToOne
@JoinColumn(name="cid")
   private Category category;
 
@OneToMany 表示一对多,fetch=FetchType.EAGER 表示不进行延迟加载(FetchType.LAZY表示要进行延迟加载)
@JoinColumn(name="cid") 表示映射字段
  private Student student;
}
 
@ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@JoinTable(
name="user_product",
joinColumns=@JoinColumn(name="uid"),
inverseJoinColumns=@JoinColumn(name="pid") 
)
private Set<Tea> teas;
对比xml中配置<set name="users" table="user_product" lazy="false">
<key column="pid" />
<many-to-many column="uid" class="User" />
</set>
 
对比xml中的多对多:
<set name="products" table="user_product" lazy="false">
<key column="uid" />
<many-to-many column="pid" class="Product" />
</set>
常见注解:
类注解:
@Entity —— 将一个类声明为一个实体bean(即一个持久化POJO类)
@Table —— 注解声明了该实体bean映射指定的表(table),目录(catalog)和schema的名字
 
属性注解:
@Id —— 注解声明了该实体bean的标识属性(对应表中的主键)。
@Column —— 注解声明了属性到列的映射。该注解有如下的属性
name 可选,列名(默认值是属性名)
unique 可选,是否在该列上设置唯一约束(默认值false)
nullable 可选,是否设置该列的值可以为空(默认值false)
insertable 可选,该列是否作为生成的insert语句中的一个列(默认值true)
updatable 可选,该列是否作为生成的update语句中的一个列(默认值true)
columnDefinition 可选,为这个特定列覆盖sql ddl片段(这可能导致无法在不同数据库间移植)
table 可选,定义对应的表(默认为主表)
length 可选,列长度(默认值255)
precision 可选,列十进制精度(decimal precision)(默认值0)
scale 可选,如果列十进制数值范围(decimal scale)可用,在此设置(默认值0)
@GeneratedValue —— 注解声明了主键的生成策略。该注解有如下属性
strategy 指定生成的策略(JPA定义的),这是一个GenerationType。默认是GenerationType. AUTO
GenerationType.AUTO 主键由程序控制
GenerationType.TABLE 使用一个特定的数据库表格来保存主键
GenerationType.IDENTITY 主键由数据库自动生成(主要是自动增长类型)
GenerationType.SEQUENCE 根据底层数据库的序列来生成主键,条件是数据库支持序列。(这个值要与generator一起使用)
generator 指定生成主键使用的生成器(可能是orcale中的序列)。
@SequenceGenerator —— 注解声明了一个数据库序列。该注解有如下属性
name 表示该表主键生成策略名称,它被引用在@GeneratedValue中设置的“gernerator”值中
sequenceName 表示生成策略用到的数据库序列名称。
initialValue 表示主键初始值,默认为0.
allocationSize 每次主键值增加的大小,例如设置成1,则表示每次创建新记录后自动加1,默认为50.
 
关系注解:
@ManyToOne 设置多对一关联
方法一
@ManyToOne(cascade={CasCadeType.PERSIST,CascadeType.MERGE})
@JoinColumn(name="外键")
public 主表类 get主表类(){return 主表对象}
方法二
@ManyToOne(cascade={CascadeType.PERSIST,CascadeType.MERGE})
@JoinTable(name="关联表名",
joinColumns = @JoinColumn(name="主表外键"),
inverseJoinColumns = @JoinColumns(name="从表外键")
)
@OneToMany 设置一对多关联。
方法一 。
“一端”配置
@OneToMany(mappedBy="“多端”的属性")
public List<“多端”类> get“多端”列表(){return “多端”列表}
“多端”配置参考@ManyToOne.
方法二
“一端”配置
@OneToMany(mappedBy="“多端”的属性")
@MapKey(name="“多端”做为Key的属性")
public Map<“多端”做为Key的属性的类,主表类> get“多端”列表(){return “多端”列表}
“多端”配置参考@ManyToOne.
方法三 使用这种配置,在为“一端”添加“多端”时,可以修改“多端”的外键。
“一端”配置
@OneToMany
@JoinColumn(name="“多端”外键")
public List<“多端”类> get“多端”列表(){return “多端”列表}
“多端”配置参考@ManyToOne.
 
 
hibernate.cfg.xml 配置文件改动
<mapping resource="com/how2java/pojo/Product.hbm.xml" />注释掉,采用:<mapping class="com.how2java.pojo.Product" />,其他代码不变
posted @ 2020-08-26 13:44  z街角的风铃y  阅读(253)  评论(0)    收藏  举报