Hibnate框架笔记
1、基本概念
1.1、简介
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的JaveEE架构中取代CMP,完成数据持久化**的重任。
- DBUtils也是对JDBC的封装
- 它将POJO与数据库表建立映射关系,是一个全自动的orm框架
- POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans
- hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
- Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用
1.2、总结Hibernate
- Hibernate是一个数据持久化层的ORM框架,它的主要功能就是把对象映射到表中,操作API,只需要将一个对象存储到数据库,不需要写sql语句
- Hibernate提供了对关系型数据库增删改成操作
1.3、orm
对象关系映射,可以认为是讲实体类与数据库表相互关联,形成对应的映射关系,使得每个人model与一张表相关联,字段与属性相互形成映射关系。
- 对象关系映射(英语:(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping)
- 对象和表字段进行对应
- 是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。
- Object:对象,java对象,此处特指JavaBean,Model
- Relational:关系,二维表,数据库中的表。
- Mapping:映射
1.4、主流ORM框架
- JPA Java Persistence API.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系(只有接口规范)
- Hibernate 最流行ORM框架,通过对象-关系映射配置,可以完全脱离底层SQL
- MyBatis 本是apache的一个开源项目 iBatis,支持普通 SQL查询,存储过程和高级映射的优秀持久层框架
- Apache DBUtils 、Spring JDBCTemplate
1.5、Hibernate的优点
- Hibernate对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码
- Hibernate对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码
- Hibernate使用java的反射机制
- Hibernate的性能非常好,因为它是一个轻量级框架。映射的灵活性很出色。它支持很多关系型数据库,有一对一到多对多的各种复杂关系映射
1.4、实体类
实体类是hibernate中的类建模规范,用entity、model、pojo表示,一般有一下要求:
- 实体类中提供无参的构造方法
- 实体类中提供每个属性的public的getter与setter方法
- 有一个可以作为主键的属性
- 属性尽量使用基本类型的包装类
- 不要用final对实体进行修饰
2、配置文件与jar包
2.1、hibernate的使用步骤
- 下载hibernate 的jar包,并导入到项目中(http://hibernate.org/orm/)
- 创建数据库和表
- 配置核心配置文件hibernate.cfg.xml【这个文件有连接数据库的配置】
- 编写映射文件hibernate mapping(*.hbm.xml),【声明对象如何关联数据库表字段】
- 调用hibernate的api
2.1、jar包
- 这里我们使用3.6.0的版本开发,4.0开发是建议使用注解
- 所需要导入的jar包,如下图,然后再导入一个mysql数据库连接驱动
- maven下的jar包
<!--hibernate支持jpa规范-->
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.2.Final</version>
</dependency>
<!--字节码增强-->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.26.0-GA</version>
</dependency>
<!--日志管理,整合log4j-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.8.0-beta4</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.4.1.Final</version>
</dependency>
<!--事物规范-->
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.transaction</groupId>
<artifactId>jboss-transaction-api_1.2_spec</artifactId>
<version>1.1.1.Final</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
2.2、配置文件
2.2.1、核心配置(hibernate.cfg.xml)
- 将hibernate.cfg.xml放入src下
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!--连接数据库的属性-->
<property name="connection.url">jdbc:mysql://localhost:3306/test?serverTimezone=Hongkong</property>
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<!--
数据库方言,每个数据库都有自己的方言。如做分页
mysql:limit
Oracle:rownum
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property>
<!--运行显示SQL语句-->
<property name="show_sql">true</property>
<!--按照格式打印出SQL语句-->
<property name="format_sql">true</property>
<!--
Hibernate映射与DDL语句策略。
update:如果操作数据库没有对应表就会自动创建表。
如果数据库字段与实体类属性不一致,则会更新表。
create:每次启动都会创建新表。
create-drop:每次启动都会创建新表,关闭会自动删除表。
validate:检查配置文件与数据库的字段,如果不一致则抛异常。
-->
<property name="hibernate.hibernate.hbm2ddl.auto">update</property>
<!--自动提交事物,对insert语句有效-->
<property name="hibernate.connection.autocommit">true</property>
<!--开启与当前线程绑定的session的功能-->
<property name="hibernate.current_session_context_class">thread</property>
<!--需要映射的配置资源-->
<!--<mapping resource="com/iotek/entity/user.hbm.xml"/>-->
</session-factory>
</hibernate-configuration>
2.2.2、核心配置(hibernate.properties)
######################
### Query Language ###
######################
## define query language constants / function names
hibernate.query.substitutions yes 'Y', no 'N'
## select the classic query parser
#hibernate.query.factory_class org.hibernate.hql.internal.classic.ClassicQueryTranslatorFactory
#################
### Platforms ###
#################
## JNDI Datasource
#hibernate.connection.datasource jdbc/test
#hibernate.connection.username db2
#hibernate.connection.password db2
## HypersonicSQL
hibernate.dialect org.hibernate.dialect.HSQLDialect
hibernate.connection.driver_class org.hsqldb.jdbcDriver
hibernate.connection.username sa
hibernate.connection.password
hibernate.connection.url jdbc:hsqldb:./build/db/hsqldb/hibernate
#hibernate.connection.url jdbc:hsqldb:hsql://localhost
#hibernate.connection.url jdbc:hsqldb:test
## H2 (www.h2database.com)
#hibernate.dialect org.hibernate.dialect.H2Dialect
#hibernate.connection.driver_class org.h2.Driver
#hibernate.connection.username sa
#hibernate.connection.password
#hibernate.connection.url jdbc:h2:mem:./build/db/h2/hibernate
#hibernate.connection.url jdbc:h2:testdb/h2test
#hibernate.connection.url jdbc:h2:mem:imdb1
#hibernate.connection.url jdbc:h2:tcp://dbserv:8084/sample;
#hibernate.connection.url jdbc:h2:ssl://secureserv:8085/sample;
#hibernate.connection.url jdbc:h2:ssl://secureserv/testdb;cipher=AES
## MySQL
#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
## Oracle
#hibernate.dialect org.hibernate.dialect.Oracle8iDialect
#hibernate.dialect org.hibernate.dialect.Oracle9iDialect
#hibernate.dialect org.hibernate.dialect.Oracle10gDialect
#hibernate.connection.driver_class oracle.jdbc.driver.OracleDriver
#hibernate.connection.username ora
#hibernate.connection.password ora
#hibernate.connection.url jdbc:oracle:thin:@localhost:1521:orcl
#hibernate.connection.url jdbc:oracle:thin:@localhost:1522:XE
## PostgreSQL
#hibernate.dialect org.hibernate.dialect.PostgreSQLDialect
#hibernate.connection.driver_class org.postgresql.Driver
#hibernate.connection.url jdbc:postgresql:template1
#hibernate.connection.username pg
#hibernate.connection.password
## DB2
#hibernate.dialect org.hibernate.dialect.DB2Dialect
#hibernate.connection.driver_class com.ibm.db2.jcc.DB2Driver
#hibernate.connection.driver_class COM.ibm.db2.jdbc.app.DB2Driver
#hibernate.connection.url jdbc:db2://localhost:50000/somename
#hibernate.connection.url jdbc:db2:somename
#hibernate.connection.username db2
#hibernate.connection.password db2
## TimesTen
#hibernate.dialect org.hibernate.dialect.TimesTenDialect
#hibernate.connection.driver_class com.timesten.jdbc.TimesTenDriver
#hibernate.connection.url jdbc:timesten:direct:test
#hibernate.connection.username
#hibernate.connection.password
## DB2/400
#hibernate.dialect org.hibernate.dialect.DB2400Dialect
#hibernate.connection.username user
#hibernate.connection.password password
## Native driver
#hibernate.connection.driver_class COM.ibm.db2.jdbc.app.DB2Driver
#hibernate.connection.url jdbc:db2://systemname
## Toolbox driver
#hibernate.connection.driver_class com.ibm.as400.access.AS400JDBCDriver
#hibernate.connection.url jdbc:as400://systemname
## Derby (not supported!)
#hibernate.dialect org.hibernate.dialect.DerbyDialect
#hibernate.connection.driver_class org.apache.derby.jdbc.EmbeddedDriver
#hibernate.connection.username
#hibernate.connection.password
#hibernate.connection.url jdbc:derby:build/db/derby/hibernate;create=true
## Sybase
#hibernate.dialect org.hibernate.dialect.SybaseDialect
#hibernate.connection.driver_class com.sybase.jdbc2.jdbc.SybDriver
#hibernate.connection.username sa
#hibernate.connection.password sasasa
#hibernate.connection.url jdbc:sybase:Tds:co3061835-a:5000/tempdb
## Mckoi SQL
#hibernate.dialect org.hibernate.dialect.MckoiDialect
#hibernate.connection.driver_class com.mckoi.JDBCDriver
#hibernate.connection.url jdbc:mckoi:///
#hibernate.connection.url jdbc:mckoi:local://C:/mckoi1.0.3/db.conf
#hibernate.connection.username admin
#hibernate.connection.password nimda
## SAP DB
#hibernate.dialect org.hibernate.dialect.SAPDBDialect
#hibernate.connection.driver_class com.sap.dbtech.jdbc.DriverSapDB
#hibernate.connection.url jdbc:sapdb://localhost/TST
#hibernate.connection.username TEST
#hibernate.connection.password TEST
#hibernate.query.substitutions yes 'Y', no 'N'
## MS SQL Server
#hibernate.dialect org.hibernate.dialect.SQLServerDialect
#hibernate.connection.username sa
#hibernate.connection.password sa
## JSQL Driver
#hibernate.connection.driver_class com.jnetdirect.jsql.JSQLDriver
#hibernate.connection.url jdbc:JSQLConnect://1E1/test
## JTURBO Driver
#hibernate.connection.driver_class com.newatlanta.jturbo.driver.Driver
#hibernate.connection.url jdbc:JTurbo://1E1:1433/test
## WebLogic Driver
#hibernate.connection.driver_class weblogic.jdbc.mssqlserver4.Driver
#hibernate.connection.url jdbc:weblogic:mssqlserver4:1E1:1433
## Microsoft Driver (not recommended!)
#hibernate.connection.driver_class com.microsoft.jdbc.sqlserver.SQLServerDriver
#hibernate.connection.url jdbc:microsoft:sqlserver://1E1;DatabaseName=test;SelectMethod=cursor
## The New Microsoft Driver
#hibernate.connection.driver_class com.microsoft.sqlserver.jdbc.SQLServerDriver
#hibernate.connection.url jdbc:sqlserver://localhost
## jTDS (since version 0.9)
#hibernate.connection.driver_class net.sourceforge.jtds.jdbc.Driver
#hibernate.connection.url jdbc:jtds:sqlserver://1E1/test
## Interbase
#hibernate.dialect org.hibernate.dialect.InterbaseDialect
#hibernate.connection.username sysdba
#hibernate.connection.password masterkey
## DO NOT specify hibernate.connection.sqlDialect
## InterClient
#hibernate.connection.driver_class interbase.interclient.Driver
#hibernate.connection.url jdbc:interbase://localhost:3060/C:/firebird/test.gdb
## Pure Java
#hibernate.connection.driver_class org.firebirdsql.jdbc.FBDriver
#hibernate.connection.url jdbc:firebirdsql:localhost/3050:/firebird/test.gdb
## Pointbase
#hibernate.dialect org.hibernate.dialect.PointbaseDialect
#hibernate.connection.driver_class com.pointbase.jdbc.jdbcUniversalDriver
#hibernate.connection.url jdbc:pointbase:embedded:sample
#hibernate.connection.username PBPUBLIC
#hibernate.connection.password PBPUBLIC
## Ingres
## older versions (before Ingress 2006)
#hibernate.dialect org.hibernate.dialect.IngresDialect
#hibernate.connection.driver_class ca.edbc.jdbc.EdbcDriver
#hibernate.connection.url jdbc:edbc://localhost:II7/database
#hibernate.connection.username user
#hibernate.connection.password password
## Ingres 2006 or later
#hibernate.dialect org.hibernate.dialect.IngresDialect
#hibernate.connection.driver_class com.ingres.jdbc.IngresDriver
#hibernate.connection.url jdbc:ingres://localhost:II7/database;CURSOR=READONLY;auto=multi
#hibernate.connection.username user
#hibernate.connection.password password
## Mimer SQL
#hibernate.dialect org.hibernate.dialect.MimerSQLDialect
#hibernate.connection.driver_class com.mimer.jdbc.Driver
#hibernate.connection.url jdbc:mimer:multi1
#hibernate.connection.username hibernate
#hibernate.connection.password hibernate
## InterSystems Cache
#hibernate.dialect org.hibernate.dialect.Cache71Dialect
#hibernate.connection.driver_class com.intersys.jdbc.CacheDriver
#hibernate.connection.username _SYSTEM
#hibernate.connection.password SYS
#hibernate.connection.url jdbc:Cache://127.0.0.1:1972/HIBERNATE
#################################
### Hibernate Connection Pool ###
#################################
hibernate.connection.pool_size 1
###########################
### C3P0 Connection Pool###
###########################
#hibernate.c3p0.max_size 2
#hibernate.c3p0.min_size 2
#hibernate.c3p0.timeout 5000
#hibernate.c3p0.max_statements 100
#hibernate.c3p0.idle_test_period 3000
#hibernate.c3p0.acquire_increment 2
#hibernate.c3p0.validate false
##############################
### Proxool Connection Pool###
##############################
## Properties for external configuration of Proxool
hibernate.proxool.pool_alias pool1
## Only need one of the following
#hibernate.proxool.existing_pool true
#hibernate.proxool.xml proxool.xml
#hibernate.proxool.properties proxool.properties
#################################
### Plugin ConnectionProvider ###
#################################
## use a custom ConnectionProvider (if not set, Hibernate will choose a built-in ConnectionProvider using hueristics)
#hibernate.connection.provider_class org.hibernate.connection.DriverManagerConnectionProvider
#hibernate.connection.provider_class org.hibernate.connection.DatasourceConnectionProvider
#hibernate.connection.provider_class org.hibernate.connection.C3P0ConnectionProvider
#hibernate.connection.provider_class org.hibernate.connection.ProxoolConnectionProvider
#######################
### Transaction API ###
#######################
## Enable automatic flush during the JTA beforeCompletion() callback
## (This setting is relevant with or without the Transaction API)
#hibernate.transaction.flush_before_completion
## Enable automatic session close at the end of transaction
## (This setting is relevant with or without the Transaction API)
#hibernate.transaction.auto_close_session
## the Transaction API abstracts application code from the underlying JTA or JDBC transactions
#hibernate.transaction.factory_class org.hibernate.transaction.JTATransactionFactory
#hibernate.transaction.factory_class org.hibernate.transaction.JDBCTransactionFactory
## to use JTATransactionFactory, Hibernate must be able to locate the UserTransaction in JNDI
## default is java:comp/UserTransaction
## you do NOT need this setting if you specify hibernate.transaction.manager_lookup_class
#jta.UserTransaction jta/usertransaction
#jta.UserTransaction javax.transaction.UserTransaction
#jta.UserTransaction UserTransaction
## to use the second-level cache with JTA, Hibernate must be able to obtain the JTA TransactionManager
#hibernate.transaction.manager_lookup_class org.hibernate.transaction.JBossTransactionManagerLookup
#hibernate.transaction.manager_lookup_class org.hibernate.transaction.WeblogicTransactionManagerLookup
#hibernate.transaction.manager_lookup_class org.hibernate.transaction.WebSphereTransactionManagerLookup
#hibernate.transaction.manager_lookup_class org.hibernate.transaction.OrionTransactionManagerLookup
#hibernate.transaction.manager_lookup_class org.hibernate.transaction.ResinTransactionManagerLookup
##############################
### Miscellaneous Settings ###
##############################
## print all generated SQL to the console
#hibernate.show_sql true
## format SQL in log and console
hibernate.format_sql true
## add comments to the generated SQL
#hibernate.use_sql_comments true
## generate statistics
#hibernate.generate_statistics true
## auto schema export
#hibernate.hbm2ddl.auto create-drop
#hibernate.hbm2ddl.auto create
#hibernate.hbm2ddl.auto update
#hibernate.hbm2ddl.auto validate
## specify a default schema and catalog for unqualified tablenames
#hibernate.default_schema test
#hibernate.default_catalog test
## enable ordering of SQL UPDATEs by primary key
#hibernate.order_updates true
## set the maximum depth of the outer join fetch tree
hibernate.max_fetch_depth 1
## set the default batch size for batch fetching
#hibernate.default_batch_fetch_size 8
## rollback generated identifier values of deleted entities to default values
#hibernate.use_identifer_rollback true
## enable bytecode reflection optimizer (disabled by default)
#hibernate.bytecode.use_reflection_optimizer true
#####################
### JDBC Settings ###
#####################
## specify a JDBC isolation level
#hibernate.connection.isolation 4
## enable JDBC autocommit (not recommended!)
#hibernate.connection.autocommit true
## set the JDBC fetch size
#hibernate.jdbc.fetch_size 25
## set the maximum JDBC 2 batch size (a nonzero value enables batching)
#hibernate.jdbc.batch_size 5
#hibernate.jdbc.batch_size 0
## enable batch updates even for versioned data
hibernate.jdbc.batch_versioned_data true
## enable use of JDBC 2 scrollable ResultSets (specifying a Dialect will cause Hibernate to use a sensible default)
#hibernate.jdbc.use_scrollable_resultset true
## use streams when writing binary types to / from JDBC
hibernate.jdbc.use_streams_for_binary true
## use JDBC 3 PreparedStatement.getGeneratedKeys() to get the identifier of an inserted row
#hibernate.jdbc.use_get_generated_keys false
## choose a custom JDBC batcher
# hibernate.jdbc.factory_class
## enable JDBC result set column alias caching
## (minor performance enhancement for broken JDBC drivers)
# hibernate.jdbc.wrap_result_sets
## choose a custom SQL exception converter
#hibernate.jdbc.sql_exception_converter
##########################
### Second-level Cache ###
##########################
## optimize cache for minimal "puts" instead of minimal "gets" (good for clustered cache)
#hibernate.cache.use_minimal_puts true
## set a prefix for cache region names
hibernate.cache.region_prefix hibernate.test
## disable the second-level cache
#hibernate.cache.use_second_level_cache false
## enable the query cache
#hibernate.cache.use_query_cache true
## store the second-level cache entries in a more human-friendly format
#hibernate.cache.use_structured_entries true
## choose a cache implementation
#hibernate.cache.region.factory_class org.hibernate.cache.infinispan.InfinispanRegionFactory
#hibernate.cache.region.factory_class org.hibernate.cache.infinispan.JndiInfinispanRegionFactory
#hibernate.cache.region.factory_class org.hibernate.cache.internal.EhCacheRegionFactory
#hibernate.cache.region.factory_class org.hibernate.cache.internal.SingletonEhCacheRegionFactory
hibernate.cache.region.factory_class org.hibernate.cache.internal.NoCachingRegionFactory
## choose a custom query cache implementation
#hibernate.cache.query_cache_factory
############
### JNDI ###
############
## specify a JNDI name for the SessionFactory
#hibernate.session_factory_name hibernate/session_factory
## Hibernate uses JNDI to bind a name to a SessionFactory and to look up the JTA UserTransaction;
## if hibernate.jndi.* are not specified, Hibernate will use the default InitialContext() which
## is the best approach in an application server
#file system
#hibernate.jndi.class com.sun.jndi.fscontext.RefFSContextFactory
#hibernate.jndi.url file:/
#WebSphere
#hibernate.jndi.class com.ibm.websphere.naming.WsnInitialContextFactory
#hibernate.jndi.url iiop://localhost:900/
2.2.3、JavaBean映射文件(className.hbm.xml)
- JavaBean与.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">
<hibernate-mapping>
<!--
name:指的是实体类模型
table:是指对应的数据库表
dynamic-insert:是否动态生成插入语句,如果没有写默认是false。此时
如果插入的数据有一些字段为空,执行insert语句时依然会插入所有字段,
如果设置此属性为true,则会根据数据库实际字段数来插入数据。
dynamic-update:是否动态生成更新语句,与dynamic-insert类似。
-->
<class name="com.iotek.entity.User" table="user" dynamic-insert="true" dynamic-update="true">
<!--
id,name指模型主键,column指数据库主键。
generator指主键策略:
increment:也是自动增长,但是会在数据库中已有id的最大值的基础上
增加1,如果没有数据则第一条数据为1.当增加到10时删除数据,则下一
条依然从1开始。但是此方式会有线程并发问题。
sequence:Oracle数据库中使用。
hilo:hibernate自己实现,几乎不用。
native:
如果是mysql数据库,则是自增,与数据库自增类似,从1开
始,自己会记住增长的值,也就是当增长到10时删掉所有数据,下一条
依然是11.
如果是Oracle,则会根据sequence来增长。
uuid:一个长字符串,需要把模型的id改为String类型的,保存的时候
不用自己设置id,hibernate会做。
assigend:需要手动设置id,如果不收的设置,存储是会报错,要求在
保存数据前设置id。
-->
<id name="id" column="id">
<generator class="native"/>
</id>
<!--
每个属性,name指模型属性,column指数据库字段,如果模型与数据库
字段一样,则可以省略column
length:设置字段长度。
type:设置属性的类型,在自动生成表格时会根据设置来生成
date类型匹配数据库date类型,显示年月日。
time类型匹配数据库time类型,显示时分秒。
datetime匹配数据库datetime类型,显示年月日时分秒。
-->
<property name="name" type="string" length="6"/>
<property name="pass"/>
<property name="age"/>
<property name="type"/>
</class>
</hibernate-mapping>
2.2.4、日志打印配置
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file hibernate.log ###
#log4j.appender.file=org.apache.log4j.FileAppender
#log4j.appender.file.File=hibernate.log
#log4j.appender.file.layout=org.apache.log4j.PatternLayout
#log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=warn, stdout
#log4j.logger.org.hibernate=info
log4j.logger.org.hibernate=debug
### log HQL query parser activity
#log4j.logger.org.hibernate.hql.ast.AST=debug
### log just the SQL
#log4j.logger.org.hibernate.SQL=debug
### log JDBC bind parameters ###
log4j.logger.org.hibernate.type=info
#log4j.logger.org.hibernate.type=debug
### log schema export/update ###
log4j.logger.org.hibernate.tool.hbm2ddl=debug
### log HQL parse trees
#log4j.logger.org.hibernate.hql=debug
### log cache activity ###
#log4j.logger.org.hibernate.cache=debug
### log transaction activity
#log4j.logger.org.hibernate.transaction=debug
### log JDBC resource acquisition
#log4j.logger.org.hibernate.jdbc=debug
### enable the following line if you want to track down connection ###
### leakages when using DriverManagerConnectionProvider ###
#log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace
# 以下为经常使用的配置,需要打印的日志可以根据需要选择
# Global logging configuration
# log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
3、API
3.1、操作步骤
- Hibernate的核心配置文件有多种形式
- hibernate.cfg.xml 通常使用xml配置文件,可以配置内容更丰富。
- hibernate.properties 用于配置key/value 形式的内容,key不能重复的。配置有很多的局限性。一般不用。【可以进入hibernate-distribution-3.6.10.Final\project\etc目录看内容】
- 加载核心配置文件
Configuration cfg = new Configuration().configure();
- 创建sessionFactory工厂对象
SessionFactory sessionFactory = cfg.buildSessionFactory();
- 创建session会话对象
Session session = sessionFactory.openSession();
- 开启事物
Transaction transaction = session.getTransaction();
transaction.begin();
- 加载执行sql操作
session.load(User.class,2);
Session.get(User.class,1);
- 提交事物
transaction.commit();
- 关闭session会话
session.close();
- 关闭sessioFactory
sessionFactory.close();
3.2、加载核心配置文件
3.2.1、直接创建对象加载
- Configuration对象
- Configuration对象就是用来加载配置文件
- Configuration对象就是用来加载配置文件
- configre()方法加载的是hibernate.cfg.xml
- 默认情况下,上面两种配置文件都需要放在src目录下
- configure(String resource)这个方法可以指定配置文件路径
Configuration cfg = new Configuration()
该方法是直接加载hibernate.propeties文件,但hibernate.propeties文件是key,value格式的,且key不可以重复,所有有局限性,故多用hibernate.cfg.xml文件作为核心文件的格式类加载配置,所有加载hibernate.cfg.xml时用下面方法
3.2.2、通过对象调用方法加载
Configuration cfg = new Configuration().configure();
后面configure方法中可以写参数用来指定核心配置文件,如果不指定则默认去classpath下找hibernate.cfg.xml文件。
3.3、添加映射文件
- 在核心配置文件中添加
<mapping resource="com/iotek/entity/user.hbm.xml"/>
- 通过Configuration对象添加
- addResource()方法
//该方法直接去加载路径资源的映射文件
cfg.addResource("URL")
- addClass()方法
//该方法内部用字符串拼接的方式来加载映射文件,所有映射文件的命名不能随意改变
cfg.addClass(User.class);
以上两种方式如果重复使用,则要看hibernate的版本,有些版本的如果重复加载同一个文件则会报错,有些版本则会覆盖掉前面的文件。
所以一般单独使用一种,防止重复加载映射文件导致程序报错
- 平时开发中:将hbm.xml映射 配置 在hibernate.cfg.xml
3.4、session与sessionFactory
3.4.1、sessionFactory
- sessionFactory是会话工厂,它是用来产生session会话的生产者,类似于是一个数据库连接池,它床建好session会话后通过会话来访问操作数据库。sessionFactory是线程安全的。
- SessionFactory 相当于java web连接池,用于管理所有session
- SessionFactory 相当于java web连接池,用于管理所有session
- sessionFactory 还用于缓存配置信息 (数据库配置信息、映射文件,预定义HQL语句 等)
- SessionFactory线程安全,多个线程同时访问时,不会出现线程并发访问问题。
- 创建方式
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
3.4.2、session会话
- session是会话,是用来与数据库建立连接,操作数据库以及对应的配置,类似于数据库连接,它是通过sessionFactory来生产的。
- 创建方式
- openSession()方法创建一个独立的session
Session session = sessionFactory.openSession();
- 要使用这个方法必须在hibernate.cfg.xml中配置
<property name="hibernate.current_session_context_class">thread</property>
- hibernate支持,将创建的session绑定到本地线程中,底层使用ThreadLocal,在程序之间共享session。
- 如果提交或者回滚事务,底层将自动关闭session
通过该方式每次都会创建一个新的session。关闭是需要手动关闭
- getCurrentSession()方式创建一个关联线程的session
Session currentSession = sessionFactory.getCurrentSession();
通过该方法会创建一个关联线程的session,只要是在同一线程内,都是同一个session。但是要使用该方式创建一个session要先在核心配置文件中进行相应的配置,否则会报错。配置如下:
<!--开启与当前线程绑定的session的功能-->
<property name="hibernate.current_session_context_class">thread</property>
在使用该方式创建的session在某些版本中必须要收到开启提价事物,且事物提交或者是回滚时session自动关闭,不需要手动关闭。
- 案例代码
3.5、事物(Transaction)
- hibernate中默认是要手动提交事物,但是也可以通过配置来实现自动提交。在框架整合之后事物的管理是交给spring来管理的。
- 手动提交事物
//获取事物对象
Transaction transaction = session.getTransaction();
User user = new User();
user.setId(3);
try {
//开启事物
transaction.begin();
//执行操作
session.delete(user);
//提交事物
transaction.commit();
}catch (Exception e){
//事物回滚
transaction.rollback();
System.out.println(e.getMessage());
}
- 自动提交事物
<property name="hibernate.connection.autocommit">true</property>
3.6、session的API(方法)
- save 保存
- get 通过id查询,如果没有 null
- load 通过id查询,如果没有抛出异常
- update 更新
- delete 删除
3.6.1、save(Object object);
向数据库插入数据,保存数据。
@Test
public void test2(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
transaction.begin();
session.save(new User("王麻子","wangmazi",(byte)30,'否'));
transaction.commit();
session.close();
sessionFactory.close();
}
3.6.2、根据id获取数据
3.6.2.1、session.get(Class,Serelizble)获取数据;
@Test
public void test2(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
transaction.begin();
User user = session.load(User.class,2);
System.out.println("*******"+user+"******");
transaction.commit();
session.close();
sessionFactory.close();
}
3.6.2.2、session.load(Class,Serelizble)加载数据;
@Test
public void test2(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
transaction.begin();
User user = session.get(User.class,2);
System.out.println("*******"+user+"******");
transaction.commit();
session.close();
sessionFactory.close();
}
3.6.2.3、load与get方法的区别
- get与load方法都是根据id来获取数据。
- 当数据库没有id参数对应的数据时,get方法会返回null,而load方法会报错。
- get方法是直接去加载数据库,而load是懒加载,到用的时候才去加载数据库。他返回的是一个代理。此代理只有一个id属性,当我们要用到对象的其他属性时它才会去加载数据库。
- get方法是直接加载数据库
- load的设计是懒加载,用到时才去查询数据库
- load方法返回的是对象的一个代理
- load执行原理图
3.6.3、删除数据
删除数据用delete(Object);实际执行是是根据传入对象的id来匹配删除的。
3.6.3.1、第一种方式:先获取数据,然后删除。
@Test
public void test5(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
User user = session.get(User.class, 2);
Transaction transaction = session.getTransaction();
try {
//开启事物
transaction.begin();
//执行操作
session.delete(user);
//提交事物
transaction.commit();
}catch (Exception e){
//事物回滚
transaction.rollback();
System.out.println(e.getMessage());
}
session.close();
sessionFactory.close();
}
3.6.3.2、第二种方式:直接创建一个带id的对象,然后删除。
@Test
public void test4(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
//获取事物对象
Transaction transaction = session.getTransaction();
User user = new User();
user.setId(3);
try {
//开启事物
transaction.begin();
//执行操作
session.delete(user);
//提交事物
transaction.commit();
}catch (Exception e){
//事物回滚
transaction.rollback();
System.out.println(e.getMessage());
}
session.close();
sessionFactory.close();
}
3.6.3.3、注意:
删除操作时要手动提交事物,因为配置的字段提交事物对于删除操作不起作用。而两种删除操作,第一种因为要先执行查询操作,所有整体效率没有第二种高。因为删除操作是根据id匹配删除的,所有直接用第二种会更好。
3.6.4、更新数据
3.6.4.1、方式一:先获取数据,然后直接调用对象属性的setter方法修改数据,然后直接提交事物,会自动更新数据。但是如果是修改了对象id时会在执行完查询后报错,如果是没有手动提交事物,则不执行更新操作,只执行查询操作。如果是自行创建对象,则没有任何操作。
@Test
public void test7(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
transaction.begin();
User user = session.get(User.class, 1);
user.setName("孙七");
transaction.commit();
session.close();
sessionFactory.close();
}
3.6.4.2、方式二:先获取数据,然后直接调用对象属性的setter方法修改数据,然后调用session.update(Object)方法,提交事物后修改数据。如果修改了id属性,则执行完查询后报错,效果同上,如果没有手动提交事物,则不执行更新操作,效果同上。如果没有先获取数据,而是自行创建数据,此时如果创建的对象在数据库没有id与之对应的数据,则会报错,提示没有对应的数据可以修改,如果有id对应的数据,则数据库设置不能为空的字段要全部赋值,否则会报错提示无法执行操作,因为字段不能为空。
@Test
public void test7(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
transaction.begin();
User user = session.get(User.class, 1);
user.setName("赵六");
session.update(user);
transaction.commit();
session.close();
sessionFactory.close();
}
3.6.4.2、方式三:先获取数据,然后直接调用对象属性的setter方法修改数据,然后调用session.save()方法。如果只是修改了id以外的字段,则调用save方法后自动提交事物,则同样执行数据更新操作。如果不手动提交事物,则只是查询操作,其他不作任何操作。如果同时修改了id字段,此时不做事物提交则只做查询操作,如果手动提交事物则报错。如果单纯的创建对象,然后调用save方法则就是单纯的插入操作。
@Test
public void test8(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
User user = session.get(User.class, 1);
user.setName("张三");
user.setId(2);
user.setPass("ddd");
user.setAge((byte)12);
user.setType('否');
transaction.begin();
session.save(user);
transaction.commit();
session.close();
sessionFactory.close();
}
3.6.4.2、方式四:先获取数据,然后修改除id外的字段,然后调用saveOrUpdate()方法。先不手动提交事物,则除了查询外不做其他操作。如果手动提交事物,则做更新操作。如果修改了id字段,则在不做事物提交的话除了查询没有其他操作,如果手动提交事务。则或报错。如果是创建对象,赋值时如果有id,则会根据id去更新,手动提交事物更新成功,如果没有找到id对应的数据会报错。如果不提交事物,则不做任何操作。如果创建的对象没有id属性,则无论是否手动提交事物都会进行直接指向插入操作。
@Test
public void test8(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
User user = new User();
//User user = session.get(User.class, 1);
user.setName("李四");
user.setPass("lisi");
user.setAge((byte)20);
user.setType('否');
//transaction.begin();
session.saveOrUpdate(user);
//transaction.commit();
session.close();
sessionFactory.close();
}
3.6.5、query使用hql查询
3.6.5.1、概念:
sql是结构化查询语言,针对数据库进行操作,而hql是面向对象的思想,与sql不同。其中查询是不用写select关键字,写查询数据源时写的是类名而不是表名。
- HQL:Hibernate Query Language的缩写,就是Hibernate的查询语言
面向对象查询语言,最终底层要转成面向数据库查询语言
SQL:直接面向数据库查询语言 - Query:用于查询的对象,可以设置查询条件个分页查询。
3.6.5.2、注意:
- idea在写hql时候会遇到编译错误:can’t resolve symbol XXX。使用快捷键ctrl+alt+s进入设置界面,按红色矩形框操作,找到JPA issues下面的Query language check将其取消勾选,或者像我一样改为Warning。
- 在hibernate4.1之后对hql做了更改,所有在做query查询时写hql语句要注意hibernate的版本。4.1之后的占位符要符号JPA-style格式。也就是占位符后面要跟上坐标值,此坐标值可以随意,赋值时对应即可。
- hql语句是面向对象的,书写格式如:from User Where name=?0 and pass=?1,在hql语句中写的是类名跟类的属性,不是表名跟字段。另外就是占位符后面的坐标值,在4.1之后不写会报错。
- 如果用sql的格式如select nam,pass,age,type from User where nam=?0 and pass=?1替换掉hql语句,则可以执行正常的查询,但是结果是object格式,不能与entity对应,如果强转会报错。
3.6.5.3、查询整个表(返回多条结果用list方法)
@Test
public void test10(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
String hql = "from User";
Query query = session.createQuery(hql);
List<User> list= query.list();
list.forEach(e-> System.out.println(e));
}
3.6.5.3、带条件的查询(返回一条数据用uniqueResult方法)
- 需要注意的是上面第三点
@Test
public void test9(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
String hql = "from User where name=?0 and pass=?1";
Query query = session.createQuery(hql);
query.setParameter(0,"李四");
query.setParameter(1,"lisi");
User user = (User) query.uniqueResult();
System.out.println(user);
}
- 占位符书写麻烦可以采用取别名的方式
@Test
public void test11(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
String hql = "from User where name=:name and pass=:pass";
Query query = session.createQuery(hql);
query.setParameter("name","李四");
query.setParameter("pass","lisi");
User user = (User) query.uniqueResult();
System.out.println(user);
}
- 在createQuery中使用sql格式的hql,需要注意的是第四点
@Test
public void test9(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
String sql = "select nam,pass,age,type from User where nam=?0 and pass=?1";
String hql = "from User where name=?1 and pass=?2";
Object o = session.createQuery(hql).setParameter(1, "李四").setParameter(2, "lisi").uniqueResult();
System.out.println(o);
/*query.setParameter(0,"李四");
query.setParameter(1,"lisi");
User user = (User) query.uniqueResult();*/
//System.out.println(user);
}
3.6.5.3、分页查询
@Test
public void test12(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
String hql = "from User";
Query query = session.createQuery(hql);
query.setFirstResult(3);
query.setMaxResults(3);
List<User> list = query.list();
list.forEach(System.out::println);
}
类似limit3,3,两个参数是通过setFirstResult(3)和setMaxResults(3)实现的。
3.6.6、Criteria查询
QBC(query by criteria)。hibernate提供纯面向对象查询语言,提供直接使用po对象操作。
- 案例代码:
- 概念:
-
PO:persistent object ,用于与数据库交互数据。–dao层 (JavaBean + hbm )
-
BO:Business object 业务数据对象。–service层
-
VO:Value Object 值对象。–web层
-
普通条件查询。等值查询
@Test
public void test13(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.eq("name","张三"));
criteria.add(Restrictions.eq("pass","zhangsan"));
User user = (User) criteria.uniqueResult();
System.out.println(user);
}
- 一般条件查询(大于小于)
@Test
public void test15(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Criteria criteria = session.createCriteria(User.class);
//gt是指大于 ge是指大于等于
criteria.add(Restrictions.gt("age",(byte)30));
//lt是指小于 le是指小于等于
criteria.add(Restrictions.lt("age",(byte)30));
criteria.list().forEach(System.out::println);
}
- 模糊查询
@Test
public void test14(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.like("pass","%a%"));
List<User> list = criteria.list();
for (User user : list) {
System.out.println(user);
}
}
3.6.7、sqlQuery
sqlQuery是原生SQL查询。并不是所有的SQL都可以用hql来代替
- 案例代码
@Test
public void test16(){
Configuration cfg = new Configuration().configure();
cfg.addClass(User.class);
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
String sql = "select * from user";
SQLQuery sqlQuery = session.createSQLQuery(sql);
//sqlQuery.setParameter(1,"张三");
//sqlQuery.setParameter(2,"zhangsan");
List<Object[]> list = sqlQuery.list();
list.forEach(e -> {
for (Object o : e) {
System.out.println(o);
}
System.out.println("=========");
});
}
使用SQLQuery查询到的结果是每行数据的结果集。返回一个集合,集合中存储的是数组对象。
3.6.7、封装获取session的工具
/**
* @Auther: 邪灵
* @Date: 2019/11/22 14:00
* @Description: hibernate工具
* @Since: 1.0
*/
public class HibernateUtil {
private static SessionFactory sessionFactory;
static {
//获取核心 配置对象
Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
//创建会话工厂
sessionFactory = configuration.buildSessionFactory();
//设置程序关闭监听
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run() {
sessionFactory.close();
System.out.println("程序关闭");
}
});
}
public static Session getSession(){
return sessionFactory.openSession();
}
public static Session getCurrentSession(){
return sessionFactory.getCurrentSession();
}
}
3.7、配置文件详解
3.7.1、hibernate.cfg.xml说解
掌握各个配置的作用
3.7.2、hbm.xml映射文件解说
实体类的编写规则
- 我们在使用Hibernate时,书写了一个User类,这个类我们称为JavaBean
- JavaBean可以简单的理解成提供私有属性,并提供私有属性的get/set方法
- POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans
- 我们也称为模型,在Hibernate中,又称这种类为实体,因为是与表关联的
编写规则
- 提供一个无参数 public访问控制符的构造器
- 提供一个标识属性 ,映射数据表主键字段,提供id
- 所有属性提供public访问控制符的 set get 方法(javaBean)
- 标识属性应尽量使用基本数据类型的包装类
- 不要用final修饰实体 (将无法生成代理对象进行优化)
持久化对象的唯一表示OID
- Java按地址区分同一个类的不同对象.
- 关系数据库用主键区分同一条记录
- Hibernate使用OID来建立内存中的对象和数据库中记录的对应关系结论: 对象的OID和数据库的表的主键对应。
- 为保证OID的唯一性,应该让Hibernate来为OID赋值
区分自然主键和代理主键 - 主键需要具备: 不为空/不能重复/不能改变
- 自然主键: 在业务中,某个属性符合主键的三个要求.那么该属性可以作为主键列.【登录名可以是自然主键】
- 代理主键: 在业务中,不存符合以上3个条件的属性,那么就增加一个没有意义的列.作为主键.
基本数据与包装类型 - 基本数据类型和包装类型对应hibernate的映射类型相同
- 基本类型无法表达null、数字类型的默认值为0。
- 包装类默认值是null。当对于默认值有业务意义的时候需要使用包装类。
SQL、Hibernate和对象类型对应
java数据类型 | hibernate数据类型 | 标准SQL数据类型 |
---|---|---|
byte、java.lang.Byte | byte | TINYINT |
short、java.lang.Short | short | SMALLINT |
int、java.lang.Integer | integer | INGEGER |
long、java.lang.Long | long | BIGINT |
float、java.lang.Float | float | FLOAT |
double、java.lang.Double | double | DOUBLE |
java.math.BigDecimal | big_decimal | NUMERIC |
char、java.lang.Character | character | CHAR(1) |
boolean、java.lang.Boolean | boolean | BIT |
java.lang.String | string | VARCHAR |
boolean、java.lang.Boolean | yes_no | CHAR(1)(‘Y’或’N’) |
boolean、java.lang.Boolean | true_false | CHAR(1)(‘Y’或’N’) |
java.util.Date、java.sql.Date date | DATE | |
java.util.Date、java.sql.Time time | TIME | |
java.util.Date、java.sql.Timestamp | timestamp TIMESTAMP | |
java.util.Calendar | calendar | TIMESTAMP |
java.util.Calendar | calendar_date DATE | |
byte[] binary | VARBINARY、BLOB | |
java.lang.String text | CLOB | |
java.io.Serializable | serializable | VARBINARY、BLOB |
java.sql.Clob | clob | CLOB |
java.sql.Blob | blob | BLOB |
java.lang.Class | class | VARCHAR |
java.util.Locale | locale | VARCHAR |
java.util.TimeZone | timezone | VARCHAR |
java.util.Currency | currency | VARCHAR |
主键生成策略
<id name="uid" column="id">
<!-- generator:id的生成策略
increment:也会自动增长id,但是它的这种增长是自己Hibernate实现
执行select max(id) 查询,这种会有线程并发问题
sequence:一般在oracle数据库才用
hilo:hibernate自己实现的id规则【不用,不用学】
native:【经常常用】
如果是mysql数据库,id会自动增长
如果是oracle数据库,会自动增长,sequence
uuid:【经常常用】一个长字符串,需要把模型的id改成字符串
保存的时候,不用自己设置ID,hibernate会设置id
assigned:【经常常用】要手动设置id属性
-->
<generator class="assigned"></generator>
</id>
普通属性
- class标签的dynamic-insert=“true” 是否动态生成插入语句,
- 【如果属性字段为空,就不会有些字段的插入语句】
- class标签的dynamic-update=“true” 与insert类似
type的使用
3.8、Hibernate实体的状态
3.8.1、状态介绍
- 实体entity有三种状态,瞬时状态,持久状态,脱管状态
- 瞬时状态:transient,session没有缓存,数据库没有记录,oid没有值。
- 持久状态:persistent,session有缓存,数据库有记录,oid有值。
- 脱管状态:detached,session没有缓存,数据库有记录,oid有值。
3.8.2、瞬时 转 持久
- 新创建的一个对象,经过save,或者savaOrUpdate调用后,会变成持久状态
3.8.3、持久 转 脱管
- load,get返回的对象是持久状态的,当session关闭或者清除后,对象变成脱管状态
3.8.4、总结状态的转换过程
- 查询操作:get、load、createQuery、createCriteria 等 获得都是持久态
- 瞬时状态执行save、update、saveOrUpdate之后变成持久状态
- 持久态 转换 脱管态
- session.close () 关闭
- session.clear() 清除所有
- session.evict(obj) 清除指定的PO对象
4、一级缓存
4.1、概念
一级缓存:又称为session级别的缓存。当获得一次会话(session),hibernate在session中创建多个集合(map),用于存放操作数据(PO对象),为程序优化服务,如果之后需要相应的数据,hibernate优先从session缓存中获取,如果有就使用;如果没有再查询数据库。当session关闭时,一级缓存销毁。
4.2、证明一级缓存
4.3、移除缓存
4.4、一级缓存快照
快照:与一级缓存存放位置是一样,对一级缓存数据备份。保证数据库的数据与 一级缓存的数据必须一致。如果一级缓存修改了,在执行commit提交时,将自动刷新一级缓存,执行update语句,将一级缓存的数据更新到数据库
4.5、快照演示(一级缓存刷新)
4.6、一级缓存的细节
- HQL的结果会进行一级缓存,SQL的结果不会添加到一级缓存
5、其他API
5.1、save和persist方法的区别
save方法:瞬时态 转换 持久态,会初始化OID
- 执行save方法,立即触发insert语句,从数据库获得主键的值(OID值)
- 执行save方法前,设置OID将忽略。
- 如果执行查询,session缓存移除了,在执行save方法,将执行insert
persist方法:瞬时态 转换 持久态
- persist保存的对象,在保存前,不能设置id,否则会报错
- save和persist都是持久化对象的作用
- save 因为需要返回一个主键值,因此会立即执行 insert 语句,而 persist 在事务外部调用时则不会立即执行 insert 语句,在事务内调用还是会立即执行 insert 语句的。
update方法
saveOrUpdate方法
判断是否有OID,如果没有OID,将执行insert语句,如果有OID,将执行update语句。
Delete方法
6、Hibernate的多表关联关系映射
6.1、回顾多表关系
- 表之间关系存在3钟:一对多、多对多、一对一。(回顾)
- 多对多关系:课程与学生
- 一对多关系:学生与成绩
- 一对一关系:学生与身份证
- 一对多:主表的主键 与 从表外键 形成 主外键关系
- 多对多:提供中间表(从表),提供两个字段(外键)分别对应两个主表。
- 一对一:主外键关系
6.2、案例:一对多、多对一
- 客户和订单的关系是一对多的关系,订单和客户的关系是多对一的关系
实体类的编写
注意:set集合一定要定义的时候初始化对象,需要提供属性的get/set方法
映射文件的编写
- Customer.hbm.xml
<hibernate-mapping package="com.gyf.hibernate.domain">
<class name="Customer" table="t_customer">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="name" length="20"></property>
<!-- 一个客户有多个定单,Hibernate可以双向描述一对多的关系
set中 name写的是实例的属性
-->
<set name="orders">
<!-- column指的是Order表中的外键 -->
<key column="customer_id"></key>
<one-to-many class="Order"/>
</set>
</class>
</hibernate-mapping>
- Order.hbm.xml
<hibernate-mapping package="com.gyf.hibernate.domain">
<class name="Order" table="t_order">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<!-- 定单名称 -->
<property name="name"></property>
<!-- 多个定单对应一个客户,Hibernate可以双向描述一对多的关系
set中 name写的是实例的属性
-->
<many-to-one name="customer" class="Customer" column="customer_id"></many-to-one>
</class>
</hibernate-mapping>
单元测试
@Test
public void test1(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
//客户
Customer customer = new Customer();
customer.setName("gyf");
//定单
Order order1 = new Order();
order1.setName("iphone8");
Order order2 = new Order();
order2.setName("iphonex");
//维护客户与定单的关系
customer.getOrders().add(order1);
customer.getOrders().add(order2);
//维护定单与客户的关系
order1.setCustomer(customer);
order2.setCustomer(customer);
session.save(customer);//执行三条insert sql语句
session.save(order1);//执行一条update sql语句,维护外键关系
session.save(order2);//执行一条update sql语句,维护外键关系
session.getTransaction().commit();
session.close();
}
设置外键维护的方式
- 修改Customer的配置文件,添加一个inverse选项
- inverse是hibernate双向关系中的基本概念。inverse的真正作用就是指定由哪一方来维护之间的关联关系。当一方中指定了“inverse=false”(默认),那么那一方就有责任负责之间的关联关系。
查询一对多和删除
一对多的查询,会执行两条SQL语句
6.3、cascade级联
save-update
级联保存,级联修改,保存A(客户)时,同时保存B(订单)
delete
级联删除,删除A时,同时删除B。
delete-orphan孤儿删除
孤儿删除,解除关系,同时将B删除,A存在的。
级联组合:
如果需要配置多项,使用逗号分隔。
all : save-update 和 delete 整合
all-delete-orphan : 三个整合
6.4、Hibernate实体状态回顾
7、Hibernate的多表关联关系映射
7.1、多对多的关联关系映射
- 目标:掌握如何多表关联的映射进行配置
- 以学生和课程为例,一个学生可以对应多个课程,多个学生可以对应一个课程
7.1.1、学生和课程的JavaBean(entity,pojo,model)
7.1.2、学生和课程表的hbm.xml映射
- Student.hbm.xml
- Course.hbm.xml
7.2、多对多的测试
7.2.1、自动生成三张表
public void test1(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
session.getTransaction().commit();
session.close();
}
7.2.2保存一个学生
- 注意保存前的外键维护和级联是如何配置
- 一般操作多的一方选择级联,这里学生操作比较多
@Test
public void test1(){
/**
* 保存多对多数据
*/
Session session = HibernateUtils.openSession();
session.getTransaction().begin();
//1.创建2个学生
Student stu1 = new Student("特朗普");
Student stu2 = new Student("普京");
//2.创建2个课程
Course c1 = new Course("维护世界和平");
Course c2 = new Course("外贸");
//3.绑定课程到学生
stu1.getCourses().add(c1);
stu1.getCourses().add(c2);
stu2.getCourses().add(c1);
stu2.getCourses().add(c2);
//4.保存
/**
* 保存的注意事项
* 1.配置级联保存,只保存学生对象
* 插入2个学生,插入2两课程,中间4条,8条sql
* 2.如果在Student配置inverse="true",由Course来维护外键关系,中间表没数据
* 3.默认Student配置inverse="false",由Student来维护外键关系,中间表有数据
* 4.多对多,inverse不能两边都为true,如果两边都为true,不管保存哪个对象,中间表都没有数据
*/
/*session.save(stu1);
session.save(stu2);*/
//课程拥有有学生
c1.getStudents().add(stu1);
c1.getStudents().add(stu2);
c2.getStudents().add(stu1);
c2.getStudents().add(stu2);
session.save(c1);
session.save(c2);
session.getTransaction().commit();
session.close();
}
7.3、加载策略
7.3.1、类级别的加载策略
- get:立即检索。get方法一执行,立即查询所有字段的数据。
- load:延迟检索。默认情况,load方法执行后,如果只使用OID的值不进行查询,如果要使用其他属性值才查询
- 如果在类级别上配置lazy为true,那load方法就会即时加载,否则为延时加载
7.3.2、关联级别的加载策略
- 关联级别的集合加载的策略是默认是懒加载
- 可以设置为即时加载,如图,即加载学生时,学生所属的课程也会加载进来
7.3.3fecth
Fecth:拿取,获取数据
fecth:是指查询集合的sql方式
select:默认的,普通select查询语句
join:表连接语句查询
subselect:使用子查询
fetch:select
- set集合默认的sql查询方式就是fectch=select,一个普通的select查询语句
fetch:join
fetch:subselect
【只能用于多对多,一对多】
7.3.4、多对一的加载策略
- 这里以Customer和Order多例来讲
- 多对一标签<many-to-one fetch="" lazy="">
7.3.5、批量加载
- set标签可以配置一个batch-size=“2”,表示每次可以加载两条数据
7.3.6检索策略
检索策略 | 优点 | 缺点 | 优先考虑使用的场合 |
---|---|---|---|
立即检索,即时加载 | 对应用程序完全透明,不管对象处于持久化状态还是游离状态,应用程序都可以从一个对象导航到关联的对象 | (1)select语句多(2)浪费内存空间 | (1)类级别(2)应用程序需要立即访问的对象(3)使用了二级缓存 |
延迟检索,懒加载的意思 | 由应用程序决定需要加载哪些对象,可以避免执行多余的select语句,以及避免加载应用程序不需要访问的对象。因此能提高检索性能,并节省内存空间。 | 应用程序如果希望访问游离状态的代理类实例,必须保证她在持久化状态时已经被初始化。 | (1)一对多或者多对多关联(2)应用程序不需要立即访问或者根本不会访问的对象 |
表连接检索 | (1)对应用程序完全透明,不管对象处于持久化状态还是游离状态,都可从一个对象导航到另一个对象。(2)使用了外连接,select语句少 | (1)可能会加载应用程序不需要访问的对象,浪费内存。(2)复杂的数据库表连接也会影响检索性能。 | (1)多对一或一对一关联(2)需要立即访问的对象(3)数据库有良好的表连接性能。 |
8、HQL查询
8.1、HQL简介
- HQL(Hibernate Query Language) 描写对象操作的一种查询语言,Hibernate特有
- HQL的语法与SQL基本一致,不同的是HQL是面向对象的查询,查询的是对象 和对象中的属性
- HQL的关键字不区分大小写,但类名和属性区分大小写
- 语法示例
SELECT 别名/属性名/表达式
FROM 实体 AS 别名
WHERE 过滤条件
GROUP BY 分组条件
HAVING 分组后的结果的过滤条件
ORDER BY 排序条件
8.2、案例1:查询所有客户
8.3 案例2:选择查询
8.4 案例3:投影查询
8.5 案例4:排序
8.6 案例5:分页
Query query = session.createQuery("from Customer");
// *** pageNum 当前页(之前的 pageCode)
query.setFirstResult(0);
// * 每页显示个数 , pageSize
query.setMaxResults(2);
8.7 案例6:聚合函数和分组查询
8.8 案例7:连接查询
INNER JOIN: 在表中存在至少一个匹配时,INNER JOIN 关键字返回行。
LEFT OUTER JOIN: 关键字会从左表 (table_name1) 那里返回所有的行,即使在右表 (table_name2) 中没有匹配的行
RIGHT OUTER JOIN:关键字会右表 (table_name2) 那里返回所有的行,即使在左表 (table_name1) 中没有匹配的行。
8.8.1 交叉连接,等效笛卡尔积
8.8.2 隐式内连接,等效SQL隐式内连接
8.8.3 内连接,等效SQL内连接
8.8.4 迫切内连接,hibernate底层使用 内连接
8.8.5 左外连接,等效SQL左外连接
8.8.6 迫切左外连接,hibernate底层使用 左外连接
8.8.7 右外连接(迫切),等效SQL右外连接
8.9 案例8:命名查询
- HQL语句写在java文件里,有时候不灵活,如果要修改语句,要重新编译项目打包
- 我们可以在hbm.xml中命名查询语句,然后java中从hbm.xml取出hql语句,这样,以后的开发,可以直接找hbm.xml进行配置
Hbm.xml
9、QBC查询
9.1 简介
QBC:Query By Criteria 条件查询,面向对象的查询的方式
9.2 简单查询
9.3 分页
9.4 排序
9.5 条件查询
9.6 离线查询
DetachedCriteria 离线查询对象,不需要使用Session就可以拼凑查询条件。一般使用在web层或service层拼凑。将此对象传递给dao层,此时将与session进行绑定执行查询。