目录
前言
在小白新手web开发简单总结(十二)-数据库连接的相关优化(事务管理)中主要学习了Spring提供的事务管理的基本知识,明白了什么是事务,Spring在事务管理的两种方式,而像一些优秀的框架Hibernate/Mybatis在平时项目中怎么去使用呢?这次先总结Hibernate
一 Hibernate
1.什么是Hibernate
Hibernate对象关系映射框架,即ORM(Object-Relational Mapping)框架。
在小白新手web开发简单总结(十二)-数据库连接的相关优化(事务管理)在验证声明式事务管理的实例(https://github.com/wenjing-bonnie/sql-web.git中的)中,其中BookManagerXmlTransactionService中有一个通过jdbcTemplate.queryForObject()来查询一个自定义的实体类对象,代码如下:
private Book getBookSQL(String table, String id) {
String sql = String.format("SELECT * FROM %s WHERE id=%s", table, id);
Book book = jdbcTemplate.queryForObject(sql, new RowMapper<Book>() {
@Override
public Book mapRow(ResultSet resultSet, int i) throws SQLException {
Book item = new Book();
item.id = resultSet.getInt(1);
item.name = resultSet.getString(2);
item.price = resultSet.getFloat(3);
item.online = resultSet.getDate(4).toString();
return item;
}
});
//在查询的过程中插入同样id的数据,如果启动了事务,则不会插入成功
return book;
}
在这个过程中我们通过RowMapper将ResultSet转换成自定义的Book对象,这种 把关系型数据库映射成Java对象的过程就是ORM。ORM不仅可以把行记录转换成JavaBean,也可以把JavaBean转换成行记录。
JdbcTemplate配合RowMapper就是一个最原始的ORM,而Hibernate就是一个成熟的自动化的ORM,Hibernate可以自动生成SQL语句,自动执行。那么就可以用Hibernate来代替JdbcTemplate进行增删改查数据库,成为一个比较常用的介于Java Bean和数据库服务器的桥梁。
Hibernate几乎支持所有的关系型数据库(RDBMS),像常见的MySQL、PostgreSQL、Oracle、Microsoft Server Database等。
2.Hibernate几个重要的类对象
Hibernate支持JDBC事务、JTA事务以及JNDI(Java命名与目录接口)。JTA和JNDI允许Hibernate与J2EE应用程序服务器相继承。
小注:JNDI:Java命名与目录接口(Java Naming and Directory Interface),可以简单理解为把资源重新进行命名,然后根据命名来找到该资源。
(1)配置对象Configuration
主要用于配置并启动Hibernate。通常只允许在应用程序初始化的时候创建。Configuration提供两个基础组件:数据库连接和类映射配置。
- 数据库连接:因为Hibernate是代替之前的JdbcTemplate,所以数据库的驱动类、url、用户名等参数都需要在这里进行配置。该配置文件为hibernate.properties和hibernate.cfg.xml;
- 类映射配置:创建对象与数据库表格之间的关系。
这样Hibernate通过Configuration的实例来指定对象-关系映射文件,并要创建SessionFactory实例。
(2)SessionFactory
对应数据源,有Configuration产生,里面封装JDBC的DataSource实例。不可随意生成多个实例:对于单数据库的应用,一般只需要生成一个SessionFactory。如果多个数据库的话,还需要为每个数据库都创建一个SessionFactory。
SessionFactory因为封装的DataSource,所以里面持有数据库连接池,每次从SessionFactory中创建一个Session的时候,其实就是从连接池中取出一个新的Connection。
线程安全,同一个实例可以被应用的多个线程共享。在SessionFactory中存放大量的预定义的SQL语句和映射元数据。
(3)Session
一个会话,用于与数据库的物理连接。里面封装一个JDBC Connection实例。从SessionFactory中获取。每次实例化都需要和数据库交互。
Session对象不应该长时间保持开启状态,非线程安全,需要按需进行创建和销毁。
Session中有一个缓存,称为Hibernate中的一级缓存,存放当前工作单元加载的持久化对象,每个Session都有自己的缓存,缓存中的对象只能被当前工作单元访问。
(4)Transaction
数据库事务接口。最底层是由事务管理器和事务(JDBC或JTA)处理。可通过一致Transaction接口来声明事务边界,可在不同的环境或容器中移植。
(5)Query和Criteria
查询,用于向数据库查询对象以及控制执行查询的过程。Query封装了一个HQL来查询,而Criteria完全封装了基于字符串形式的查询语句,比Query更面向对象,擅长动态查询。该类中包含了数据库最后查询的数据。
二 实例
仍然在https://github.com/wenjing-bonnie/sql-web.git的基础上进行添加代码。就是简单的去实现一个往一个新表librarian中增加图书管理员。
- 1.要使用Hibernate,理所当然的要在pom.xml中增加相应的依赖
<!--hibernate-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.12.Final</version>
</dependency>
<!--Spring ORM 包含Spring对DAO特性集进行了扩展-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
spring-orm这个jar文件包含Spring对DAO特性集进行了扩展,使其支持 iBATIS、JDO、OJB、TopLink,因为Hibernate已经独立成包了,现在不包含在这个包里了。这个jar文件里大部分的类都要依赖spring-dao.jar里的类,用这个包时你需要同时包含spring-dao.jar包。
- 2.创建表的实体类Librarian
具体就是一些表对应的字段以及get/set方法,具体的代码可参见com.wj.hsqldb.model.Librarian中的代码。
@Entity
public class Librarian {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int age;
private String sex;
public void setId(Long id) {
this.id = id;
}
@Id
public Long getId() {
return id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getSex() {
return sex;
}
@Override
public String toString() {
return "Librarian{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
注意该类必须使用增加javax.persistence.Entity注解,否则会抛出org.hibernate.MappingException: Unknown entity: com.wj.hsqldb.model.Librarian异常。
遗留问题:肯定有一种方式是可以直接将数据库的表转换成实体类对象,只不过现在不知道该怎么弄,后面去了解下
- 3.创建Spring的配置文件application-context-hibernate.xml
因为Hibernate只是一个对象关系映射框架,只是解决之前我们通过jdbcTemplate.queryForObject()中的通过RowMapper将ResultSet转换成自定义的对象,所以在进行读写数据库的事务管理、数据源仍需要和前面小白新手web开发简单总结(十二)-数据库连接的相关优化(事务管理)中进行依次添加事务管理,只不过现在事物的PlatformTransactionManager就是上次没有具体介绍的org.springframework.orm.hibernate5.HibernateTransactionManager。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--增加数据库配置的配置文件-->
<context:property-placeholder location="classpath:config/jdbc.properties"/>
<context:component-scan base-package="com.wj.hsqldb"/>
<!--配置数据源-->
<bean id="hiDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="initialPoolSize" value="3"/>
<property name="maxPoolSize" value="6"/>
</bean>
<!--添加SessionFactory-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="hiDataSource"/>
<!--<property name="mappingResources"> 指定classpath下具体映射文件名或者利用list同时指定多个 映射文件
mappingLocations:可以指定任何文件路径,并且可以指定前缀:classpath、file等
-->
<!-- <property name="mappingLocations">-->
<!-- <value>com/wj/hsqldb/model/Librarian.hbm.xml</value>-->
<!-- </property>-->
<property name="packagesToScan">
<list>
<value>com.wj.hsqldb.model</value>
</list>
</property>
<!--(第一种)也可以通过配置properties的方式来配饰-->
<!-- <property name="hibernateProperties">-->
<!-- <props>-->
<!-- <prop key="dialect"></prop>-->
<!-- </props>-->
<!-- </property>-->
<!--(第二种)也可以通过配置properties的方式来配饰-->
<property name="configLocation" value="classpath:config/hibernate.cfg.xml"/>
</bean>
<!--配置Spring事务-->
<bean id="hiTransactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 配置事务属性-->
<tx:advice id="txAdvice" transaction-manager="hiTransactionManager">
<tx:attributes>
<tx:method name="get*"/>
<tx:method name="*Librarian"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--配置事务切入点-->
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.wj.hsqldb.service.LibrarianManagerService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
</beans>
区别在于:
(1)事务管理引用的属性发生变化:在HibernateTransactionManager中增加<property name="sessionFactory">;而在DataSourceTransactionManager 中增加<property name="dataSource">
(2)额外需要增加LocalSessionFactoryBean的定义:其中有几个属性
<property name="dataSource">配置SessionFactory的数据源
<property name="packagesToScan">指定.hbm.xml中文件所在的路径
<property name="configLocation" >配置Hibernate的配置文件或者通过<property name="hibernateProperties">直接读取.properties文件中的配置项
- 4.Hibernate的配置文件hibernate.cfg.xml
该Hibernate配置项,其实有两种实现方式:
一种是通过.properties的方式,在application-context-hibernate.xml中通过 <property name="hibernateProperties">来读取;
另外一种方式就是增加hibernate.cfg.xml文件,在application-context-hibernate.xml中通过 <property name="configLocation">来读取
具体的配置内容如下:
<?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:hsqldb:file:db/hsqldb/xbook</property>-->
<!-- <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>-->
<!-- <property name="connection.username">SA</property>-->
<!-- <property name="connection.password"></property>-->
<!--转换为合适的数据库语句-->
<property name="dialect">org.hibernate.dialect.HSQLDialect</property>
<!--是否显示sql语句-->
<property name="hibernate.show_sql">true</property>
<!--update:只是更新,没有就创建;create:每次都是新创建;create-drop用完就会删除表-->
<!--我现在理解的是update用完一次要记得隐藏-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!--下一层级的映射关系,用来配置JavaBean与数据库之间的关系-->
</session-factory>
</hibernate-configuration>
从隐藏的代码可以看到里面也可以配置数据库的一些url、用户名等属性,但是和前面的 application-context-hibernate.xml中的配置不能重复。主要说明下里面的几个属性:
(1)"hibernate.hbm2ddl.auto":是否依赖hibernate来建表
<property name="hibernate.hbm2ddl.auto">update</property>
其中hibernate.hbm2ddl.auto几个参数的作用如下:
- create:每次加载hibernate都会删除上一次生成的表,然后根据Java对象重新生成新表,会导致数据库数据丢失
- create-drop:每次加载hibernate根据Java对象生成表,但SessionFactory一关闭,表就会自动删除
- update:第一次加载hibernate会根据Java对象自动建立起表结构(前提是已经建立好数据库),若没有的话,会自动创建新表。以后加载hibernate时根据Java对象自动更新表结构,即使表结构发生变化仍然不会删除以前的行
- validate:每次加载hibernate时,会和数据库中的表进行标记,不会创建新表,但会插入新值
遗留问题:该属性特别是update在使用的过程中,发生只在项目第一次运行的时候,如果对于数据库的内容没有任何更新,则需要把“<property name="hibernate.hbm2ddl.auto">update</property>”给隐藏,否则会抛出异常“java.sql.SQLSyntaxErrorException”
Caused by: java.sql.SQLSyntaxErrorException: object name already exists: LIBRARIAN in statement [create table Librarian (id bigint not null, age integer not null, name varchar(255), sex varchar(255), primary key (id))]
at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source)
从SQL语句可以看到,在update中执行的命令为 “create table” ,还不是“create table if not exist”。不知道有没有额外的添加属性可以解决这个数据库不发生变化的情况
(2)"dialect":方言。对应每个具体的数据库,为具体的数据库生成对应的SQL语句。
<property name="dialect">org.hibernate.dialect.HSQLDialect</property>
列举下不同的数据库对应的方言,也就是该属性的配置值:
数据库 | 方言 |
DB2 | org.hibernate.dialect.DB2Dialect |
HSQLDB | org.hibernate.dialect.HSQLDialect |
HypersonicSQL | org.hibernate.dialect.HSQLDialect |
Informix | org.hibernate.dialect.InformixDialect |
Ingres | org.hibernate.dialect.IngresDialect |
Interbase | org.hibernate.dialect.InterbaseDialect |
Microsoft SQL Server 2000 | org.hibernate.dialect.SQLServerDialect |
Microsoft SQL Server 2005 | org.hibernate.dialect.SQLServer2005Dialect |
Microsoft SQL Server 2008 | org.hibernate.dialect.SQLServer2008Dialect |
MySQL | org.hibernate.dialect.MySQLDialect |
Oracle (any version) | org.hibernate.dialect.OracleDialect |
Oracle 11g | org.hibernate.dialect.Oracle10gDialect |
Oracle 10g | org.hibernate.dialect.Oracle10gDialect |
Oracle 9i | org.hibernate.dialect.Oracle9iDialect |
PostgreSQL | org.hibernate.dialect.PostgreSQLDialect |
Progress | org.hibernate.dialect.ProgressDialect |
SAP DB | org.hibernate.dialect.SAPDBDialect |
Sybase | org.hibernate.dialect.SybaseDialect |
Sybase Anywhere | org.hibernate.dialect.SybaseAnywhereDialec |
(3)hibernate.show_sql:是否显示SQL语句
<property name="hibernate.show_sql">true</property>
- 5.增加映射配置文件Librarian.hbm.xml
一般放到实体类所在的包下。这个文件主要是建立表与类之间的映射关系。
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.wj.hsqldb.model">
<class name="com.wj.hsqldb.model.Librarian" table="librarian">
<id name="id" type="long" column="id">
<generator class="identity"></generator>
</id>
<property name="name" type="string" column="name"/>
<property name="age" type="java.lang.Integer" column="age"/>
<property name="sex" type="java.lang.String" column="sex"/>
</class>
</hibernate-mapping>
其他的都比较容易理解,主要看下下面这个主键生成策略的属性
<generator class="increment"></generator>
其中generator有下面的几种属性:
- identity:递增。使用数据库提供的主键生成机制。如DB2、SQL Sever MySQL的主键生成机制,也就是使用递增序列在建表的时候需要对主键设置为auto_increment;
- sequence:使用数据库提供的sequence机制生成主键,如Oracle数据库
- hilo:有hi/lo算法实现的主键生成机制,需要额外的数据库表保存主键生成历史状态
- native:有Hibernate根据底层数据库自行判断使用 identity、hilo、sequence其中一种作为主键,有底层方言产生。
- seqhilo:与hilo类似,只是主键的历史保存在Sequence中,适用于支持Sequence的数据库,如Oracle
- increment:主键按数值顺序递增。实现机制是在当前应用实例中维持一个变量,以保存当前的最大值,之后每次都在这基础上加1;但是当前有多个实例来访问同一数据库,可能会造成主键重复
- assigned:有外部程序生成,无需Hibernate参与
- foreign:使用外部表的字段作为主键
- uuid.hex:基于128位唯一值产生算法生成16进制数值作为主键
- uuid.string:与uuid.hex类似,但是生成的主键未编码
在这个过程中,一开始创建的Librarian.hbm.xml里面出现table以及数据库字段出现报红色,可参见Hibernate中的Librarian.hbm.xml文件里面的table以及字段显示红色-IDEA配置DataSource
遗留问题:有可以自动生成.hbm.xml文件的方法,但是需要后面再去看下。
- 6.创建操作数据库的LibrarianManagerService
在该类中引入 SessionFactory,通过SessionFactory获取到Session,从而读写数据库。
@Component
public class LibrarianManagerService {
private String tableName = "librarian";
@Resource
private SessionFactory sessionFactory;
private Session getSession() {
return sessionFactory.getCurrentSession();
}
/**
* TODO id到底怎么进行自增???
*
* @return
*/
public void insertLibrarian(Librarian librarian) {
String sql = String.format("SELECT * FROM %s", tableName);
List<Librarian> librarians = getSession().createSQLQuery(sql).addEntity(Librarian.class).list();
if (librarians == null || librarians.isEmpty()) {
librarian.setId(new Long(1));
} else {
librarian.setId(new Long(librarians.size() + 1));
}
//使用Session
getSession().save(librarian);
//使用HibernateTemplate
//hibernateTemplate.save(librarian);
}
/**
* 获取所有的管理员
*
* @return
*/
public List<Librarian> getLibrarian() {
String sql = String.format("SELECT * FROM %s", tableName);
Query query = getSession().createSQLQuery(sql).addEntity(Librarian.class);
return query.list();
}
//取得持久化对象的方法: get() load()
//持久化对象保存,更新和删除:save(),update(),saveOrUpdate(),delete()
}
遗留问题:真正的在项目中的自增id,怎么插入对象?
- 7.创建相应的Servlet和.jsp文件来完成业务逻辑
增加具体的业务逻辑,这里仅仅简单的去实现一个将Librarian中的姓名、年龄、性别信息保存到对应的表中,之后在查询数据库中的数据。具体的类对应com.wj.hsqldb.controller。LibrarianController和addlibrarian.jsp,代码不在罗列,可直接去github上查看https://github.com/wenjing-bonnie/sql-web.git对应的代码的tag为example13-1(因为项目在一直更新,所以通过打tag的方式来标记这次代码)
通过IDEA的tomcat运行项目之后,可直接通过http://localhost:8080/librarian/addlibrarian.jsp进入到对应的页面,点击保存之后,就会在IDEA对应的日志输出数据库的数据。
三 HibernateTemplate
当然Spring中也提供了HibernateTemplate针对上述过程进行了封装,简化了数据访问的过程(即封装了从SessionFactory中获取到session,以及对Session进行管理的过程等),并支持单条SQL的事务管理。
注意这里的HibernateTemplate一般出现在DAO层,所谓对事务的管理,仅仅是针对单条SQL而言,也就是该单条SQL语句有可能含有多次数据库的操作,也就是仅针对Service层。而对于业务逻辑层的事务处理(针对业务逻辑出现的调用DAO层的组合)还是要交给Spring的事务管理。
所以相对于二 实例中只是替换了LibrarianManagerService的session去读写数据库的逻辑,其实在LibrarianManagerService中的session逻辑是不完善的,应该还有一些session的管理:譬如一些属性的设置、打开、释放等操作。所以HibernateTemplate更多是增加了这些逻辑封装,仅仅通过HibernateTemplate对象的调用就可以完成数据库的操作。
所以Session与HibernateTemplate之间的对比关系可参照JdbcTemplate和Conection之间的关系。
使用过程无非在原来基础上增加HibernateTemplate
<!--增加HibernateTemplate-->
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate5.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
具体使用可参见 com.wj.hsqldb.service.LibrarianManagerService的相关代码,从代码中可以看出使用HibernateTemplate比单纯使用Session要简便更多,像查询功能,直接就可以获得相应的实体类集合:
List<Librarian> result = hibernateTemplate.loadAll(Librarian.class);
代码不在罗列,可直接去github上查看https://github.com/wenjing-bonnie/sql-web.git对应的代码的tag为example13-2(因为项目在一直更新,所以通过打tag的方式来标记这次代码)
四 总结
在这个实例过程中遇到一些问题,简单总结下。
- 1.通过session.save()来插入数据抛出org.hibernate.MappingException: Unknown entity: com.wj.hsqldb.model.Librarian异常。
现象:运行项目的时候,在浏览器中报错信息如下:
原因:映射的实体对象需要增加javax.persistence.Entity注解。
解决方案:在Librarian类中增加@Entity的注解。同时会提示要指定一个@Id属性,只需要根据报错提示一步一步完成即可。
- 2.通过session.createSQLQuery()来查询数据,循环遍历集合元素时,抛出java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com.wj.hsqldb.model.Librarian
原查询代码如下:
public List<Librarian> getLibrarian() {
String sql = String.format("SELECT * FROM %s", tableName);
Query query = getSession().createSQLQuery(sql);
return query.list();
}
然后循环输出getLibrarian()返回的集合元素。
现象:运行项目的时候,在浏览器中报错信息如下:
原因: query.list()返回的就是List<Object>类型
解决方案:在session.createSQLQuery()后面增加相应的实体类的类型,修改之后的代码如下:
Query query = getSession().createSQLQuery(sql).addEntity(Librarian.class);
扩展:其实在hibernate的Session中提供了两个查询的方法:一个就是createSQLQuery(),另一个是createQuery(),这两个方法都可以返回数据库中的对应表中符合条件的数据,但是两个是有一定区别的:
createSQLQuery():sql语句查询;查询之后的数据以数组进行存储;需要通过addEntity()进行转换成实体对象类型的集合
createQuery():hql语句查询;查询之后的数据以List进行存储;可直接返回对应实体对象类型的集合
具体使用方式如下:
通过createSQLQuery()查询数据之后返回实体对象的集合如下:
public List<Librarian> getLibrarian() {
//sql语句
String sql = String.format("SELECT * FROM %s", tableName);
//createSQLQuery
Query query = getSession().createSQLQuery(sql).addEntity(Librarian.class);
//调用.list()返回集合
return query.list();
}
而通过 createQuery()查询之后返回实体对象的集合如下:
public List<Librarian> getLibrarian() {
//hql语句
String hql = String.format("from Librarian %s ", tableName);
//调用createQuery
Query<Librarian> other = getSession().createQuery(hql, Librarian.class);
//调用.list()返回集合
return other.list();
}
通过这两种方式可以看到最后Hibernate执行的语句也是不同的:一个直接执行SQL语句,而一个执行的是hql语句。
= createSQLQuery =
Hibernate: SELECT * FROM librarian
Librarian{id=1, name='小刘', age=34, sex='女'}
Librarian{id=2, name='小刘', age=23, sex='男'}
Librarian{id=3, name='六', age=78, sex='男'}
= createQuery =
Hibernate: select librarian0_.id as id1_0_, librarian0_.age as age2_0_, librarian0_.name as name3_0_, librarian0_.sex as sex4_0_ from Librarian librarian0_
Librarian{id=1, name='小刘', age=34, sex='女'}
Librarian{id=2, name='小刘', age=23, sex='男'}
Librarian{id=3, name='六', age=78, sex='男'}
- 3. IDEA运行Tomcat的时候控制台报出“Failed to load class "org.slf4j.impl.StaticLoggerBinder”,并且控制台无法打印出现运行异常未启动项目的log日志
现象: 在运行Tomcat的时候,控制台报出“Failed to load class "org.slf4j.impl.StaticLoggerBinder”,并且当未成功启动项目的时候,无法查看log日志(增加截图!!!!!!!!)
原因:根据提示进入到http://www.slf4j.org/codes.html#StaticLoggerBinder%C2%A0(增加截图!!!!!!!),发现缺少slf4j-nop.jar slf4j-simple.jar, slf4j-log4j12.jar, slf4j-jdk14.jar or logback-classic.jar 其中一个,并且只能添加到项目中一个。
解决方案:在pom.xml中增加相应的其中一个依赖(替换下!!!!!!!!换成slf4j-log4j12.jar)
<!--Failed to load class "org.slf4j.impl.StaticLoggerBinder"
还可以让tomcat的输出启动不成功的日志-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.5</version>
<scope>compile</scope>
</dependency>
- 4.IDEA中的Librarian.hbm.xml中的数据库table 名字以及数据库字段报红色
具体可参见Hibernate中的Librarian.hbm.xml文件里面的table以及字段显示红色-IDEA配置DataSource
- 5.Hibernate的知识点汇总
(1)Hibernate是一个对象映射关系的框架,类似的还有Mybatis等,还需要增加相应的数据源、事务来协助读写数据库;
(2)Hibernate通过配置文件加载SessionFactory,并且配置SessionFactory相关属性;
(3)SessionFactory中含有DataSource,需要专门的事务管理,并且需要将SessionFactory配置到该事务管理中;
(4)Session中含有Connection,用来生成一个读写数据库的连接;
(5)Hibernate通过.hbm.xml来映射表和对象直接关系,通过该文件放到对象的相应包下;
(6)Query和Criteria为含有数据查询的结果;
(7)HibernateTemplate可以是对读写数据库和关系映射的过程进一步封装,并且对单次的SQL增加了事务管理,但是对于业务逻辑相关的事务管理还需要依赖Spring。
- 6.遗留问题
(1)肯定有一种方式是可以直接将数据库的表转换成实体类对象,只不过现在不知道该怎么弄,后面去了解下
(2)可以自动生成.hbm.xml文件的方法,但是需要后面再去看下。
因为项目进度的需要,暂时先不了解Mybatis,先去看下业务逻辑相关的Controller和jsp文件的优化。