单独使用hibernate,遇到了很多问题,找不到hbm.xml,hibernate连接数据库失败。。。。。。现一一记录如下:
pom.xml的关键配置如下:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- 导入Mysql数据库链接jar包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
</dependencies>
1.这里我的hibernate和mysql驱动都用的是最新版本,配合使用没啥问题,但二者版本相差太大,可能会连接数据库失败
hibernate.cfg.xml文件配置:
<?xml version="1.0" encoding="GBK"?>
<!-- 指定Hibernate配置文件的DTD信息 -->
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!-- hibernate- configuration是连接配置文件的根元素,配置会话工厂,hibernate的核心对象,管理数据库连接池
hibernate.cfg.xml中不支持db.properies配置,但可以用db.properties代替 hibernate.cfg.xml的配置-->
<hibernate-configuration>
<session-factory>
<!-- 指定连接数据库所用的驱动 -->
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<!-- 指定连接数据库的url,hibernate连接的数据库名 -->
<property name="connection.url">jdbc:mysql://localhost:3306/lmeeting?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false</property>
<!-- 指定连接数据库的用户名 -->
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<!-- 指定连接数据库的密码 -->
<!-- 指定连接池里最大连接数 -->
<property name="hibernate.c3p0.max_size">20</property>
<!-- 指定连接池里最小连接数 -->
<property name="hibernate.c3p0.min_size">1</property>
<!-- 指定连接池里连接的超时时长 -->
<property name="hibernate.c3p0.timeout">5000</property>
<!-- 指定连接池里最大缓存多少个Statement对象 -->
<property name="hibernate.c3p0.max_statements">100</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
<property name="hibernate.c3p0.validate">true</property>
<!-- 指定数据库方言 ,解决数据库之间的区别MySQLInnoDBDialect该配置会造成死锁-->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- <property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>-->
<!-- 根据需要自动创建数据表 -->
<property name="hbm2ddl.auto">update</property>
<!-- 显示Hibernate持久化操作所生成的SQL -->
<property name="show_sql">true</property>
<!-- 将SQL脚本进行格式化后再输出 -->
<property name="hibernate.format_sql">true</property>
<!-- 罗列所有的映射文件 -->
<mapping resource="UserEntity.hbm.xml"/>
</session-factory>
</hibernate-configuration>
UserEntity:
public class UserEntity {
private int id;
private String account;
private String password;
private String name;
private String facepic;
private Integer companyId;
}
UserEntity.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>
<class name="com.ssh.domain.UserEntity" table="user" schema="lmeeting">
<id name="id">
<column name="id" sql-type="int(11)"/>
</id>
<property name="account">
<column name="account" sql-type="varchar(25)" length="25" not-null="true"/>
</property>
<property name="password">
<column name="password" sql-type="varchar(25)" length="25" not-null="true"/>
</property>
<property name="name">
<column name="name" sql-type="varchar(25)" length="25" not-null="true"/>
</property>
<property name="facepic">
<column name="facepic" sql-type="varchar(255)" not-null="true"/>
</property>
<property name="companyId">
<column name="company_id" sql-type="int(11)" not-null="true"/>
</property>
</class>
</hibernate-mapping>
我的测试代码:Test类
存储数据:
public class Test {
UserEntity userEntity=new UserEntity();
Configuration configuration=new Configuration().configure();
//,读取连接参数(数据库方言,hbm加载,)sessionFactory内置连接池,创建会话连接工厂
SessionFactory sessionFactory=configuration.buildSessionFactory();
//创建会话(从连接池随机选择一个连接,构建session对象【会话】,一会话--一连接【一级缓存】)
Session session=sessionFactory.openSession();
//开启事务,等价于connect.setAutoCommit(false)
Transaction transaction= session.beginTransaction();
@org.junit.Test
public void test(){
//实例化配置对象,Configuration()方法加载hbm.properties文件的,configure()方法加载配置文件hibernate.cfg.xml
userEntity.setAccount("32432fdfdg");
userEntity.setCompanyId(3);
userEntity.setFacepic("/koi");
userEntity.setName("wf");
userEntity.setPassword("wfeegf3434");
System.out.println(userEntity);
System.out.println(userEntity);
session.save(userEntity);
//createCricia()条件查询
// 提交事务
transaction.commit();
//关闭资源,将连接放回连接池
session.close();
//关闭连接池
sessionFactory.close();
}
}
2.将xxx.hbm.xml放在resource目录下能找到,但是放在domain包下就会找不到:
由于我们设定了src文件夹是存放代码的,resource文件夹是存放资源的,因此intellij在编译的时候会忽略src文件夹下面的xml文件,导致最后发布的文件夹下面丢失了这些映射文件。解决办法(pom中加入配置):
更改hibernate.cfg.xml中的配置:
<!-- 罗列所有的映射文件 -->
<mapping resource="com/ssh/domain/UserEntity.hbm.xml"/>
解决增删改查------------------------------------查询问题
更新account字段。
UserEntity userEntity=session.get(UserEntity.class,45);
userEntity.setAccount("lmj");
session.update(userEntity);
根据id删除数据:
UserEntity userEntity=session.get(UserEntity.class,45);
//或者 userEntity.setId(45);它要求hbm.xml配置的除了id外的其他属性not-null="false"
//该方法只能根据id进行删除
session.delete(userEntity);
查询数据:
//根据id查询数据
UserEntity userEntity=session.get(UserEntity.class,45);
hibernate自带的是 OID查询。【OID查询就是根据id查询某一条记录】
HQL查询
复杂查询用的比较多:
查询所有:
// 1、得到Query对象,并写入hql语句
Query query = session.createQuery("from UserEntity ");
//2、使用Query对象的list方法得到数据集合
List<UserEntity> list = query.list();
//3、遍历集合获取数据
for (UserEntity user: list) {
System.out.println(user.getAccount());
}
transaction.commit();
根据条件查询:
// 1、得到Query对象,并写入hql语句
Query query = session.createQuery("from UserEntity where name = ?0 and companyId =?1");
//2、填写上一步中占位符的内容
query.setParameter(0, "ferre");
query.setParameter(1, 78);
//3、使用Query对象的list方法得到数据集合
List<UserEntity> list = query.list();
//3、遍历集合获取数据
for (UserEntity user : list) {
System.out.println(user);
}
别名查询:
// 为查询出来的字段设置别名
String hql="from UserEntity where name = :name and companyId =:cpnId";
Query createQuery = session.createQuery(hql);
List<UserEntity> list = createQuery
.setParameter("name", "ferre")
.setParameter("cpnId", 78)
.list();
//3、遍历集合获取数据
for (UserEntity user : list) {
System.out.println(user.getCompanyId());
}
模糊查询:
// 1、得到Query对象,并写入hql语句
Query query = session.createQuery("from UserEntity where name like ?0");
// 2、填写上一步中占位符的内容
query.setParameter(0, "%啊%");
// 3、使用Query对象的list方法得到数据集合
List<UserEntity> list = query.list();
// 3、遍历集合获取数据
for (UserEntity user : list) {
System.out.println(user.getName());
}
排序查询:
//order by id desc降序 asc升序
Query query = session.createQuery("from UserEntity where name like ?0 order by id desc ");
// 2、填写上一步中占位符的内容
query.setParameter(0, "%啊%");
分页查询:(客户端发请求,查第三页,每页显示2条内容)
// 1、得到Query对象,并写入hql语句
Query query = session.createQuery("from UserEntity ");
//2、使用Query的方法实现分页
//2.1设置第一个要查询的位置(计算公式:(当前页数-1)*每页的记录数)
query.setFirstResult(3);
//2.2设置每页显示的最大记录数
query.setMaxResults(2);
// 2、使用Query对象的list方法得到数据集合
List<UserEntity> list = query.list();
// 3、遍历集合获取数据
for (UserEntity user : list) {
System.out.println(user);
}
聚集函数:
// 1、得到Query对象,并写入hql语句
Query query = session.createQuery("select count(*) from UserEntity ");
//2、获取结果(结果为long类型)
Object obj = query.uniqueResult();
//3、转化为long(类型为long,转为int会报错)
Long long1 = (Long) obj;
int count = long1.intValue();
System.out.println(count);
使用查询对象Criteria进行条件查询。当没有查询条件时,查询所有
//声明Criteria对象传入一个持久化类对象类型
Criteria criteria=session.createCriteria(User.class);
//查询使用list方法
List<User>=criteria.list();
条件查询:
//声明Criteria对象传入一个持久化类对象类型
Criteria criteria=session.createCriteria(Login.class);
//添加查询条件 Restrictions.eq是等于的意思,2个参数,第一个为持久化类的属性,第2个为比较的参数值
criteria.add(Restrictions.eq("username", "Tom"));
//查询使用list方法
result=criteria.list();
criteria.add(Restrictions.between("age", 23, 25));
///年龄在大于等于25
criteria.add(Restrictions.le("age", 25));
//年龄小于等于23
criteria.add(Restrictions.ge("age", 23));
criteria.add(Restrictions.or(Restrictions.eq("age", 23), Restrictions.like("username", "%李%")));
//或者以下写法直接使用SQL语句
criteria.add(Restrictions.sqlRestriction("age=20 or username like '%李%'"));
参考文章:https://www.cnblogs.com/liunanjava/p/4340103.html
//4.年龄在21,23,25的记录
//criteria.add(Restrictions.in("age", new Integer []{21,23,25}));
//按年龄降序排序
criteria.addOrder(Order.desc("age"));
hibernate再自动生成sql语句时,将自动过滤掉对象的空属性,根据有非空属性的属性生成查询
分页
//声明一个集合用来接收结果
List<Login> result=null;
//声明Criteria对象传入一个持久化类对象类型
Criteria criteria=session.createCriteria(Login.class);
//加入查询条件
//总记录数
//criteria.setProjection(Projections.rowCount());
//平均年龄
//criteria.setProjection(Projections.avg("age"));
//分组
criteria.setProjection(Projections.groupProperty("username"));
//查询使用list方法
result=criteria.list();
//System.out.println("平均年龄:"+result.iterator().next());
//System.out.println("总记录数:"+result.iterator().next());
Iterator iterator=result.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
分页查询:
//声明Criteria对象传入一个持久化类对象类型
Criteria criteria=session.createCriteria(Login.class);
//起始记录数
criteria.setFirstResult((pageIndex-1)*pageSize);
//每页显示最大记录数
criteria.setMaxResults(pageSize);
//查询使用list方法
List<Login> result=criteria.list();
关联查询:
//使用hql语句关联查询
String hql="select u.userName, u.telephone, u.address, g.goodsName from Users u, Goods g where u.userId=g.userId";
//必须调用 session.createSQLQuery();方法
sql: select s.id,s.name,sc.score from student as s,score as sc where s.id = sc.userId;
//调用 session.createQuery();
HQL: select s.id,s.name,sc.score from Student as s,Score as sc where s.id = sc.userId;
为字段取别名:
criteria.createAlias("departureAirport", "departureAirport");
构造集合查询类,可以关联查询:
Criteria criteria = session.createCriteria(Pass.class);
criteria = criteria.createAlias("user", "u");
criteria = criteria.add(Property.forName("u.id").eq(101));
List<Pass> list = criteria.list();
最后总结下查询:
sql语句查询,hql语句查询,Criteria对象查询
这是一个辣眼睛的问题:
Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
1.spring整合hibernate时必须在spring的配置文件中给service层加上事务配置,否则该层的所有事务的权限都只有read-only.
事实上没有配置,或者通过TransactionManager授权的类权限只有read-only.
解决办法:给相应方法,类添加事务操纵权限:
<!--Hibernate的session丢失解决方法hibernate4.support.OpenSessionInViewFilter -->
<filter>
<filter-name>openSessionInView</filter-name>
<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
<!-- <init-param>
<param-name>singleSession</param-name>
<param-value>false</param-value>
</init-param>-->
<init-param>
<param-name>flushMode</param-name>
<param-value>AUTO</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>openSessionInView</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
application.xml:
<!-- 配置事务 -->
<bean name="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="create*" propagation="REQUIRED" />
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="import*" propagation="REQUIRED" />
<tx:method name="*" propagation="REQUIRED"/>
<!--这里如果觉着麻烦只要最后一行*就可以了,因为他会扫描所有的函数的 -->
</tx:attributes>
</tx:advice>
<aop:config proxy-target-class="true">
<!-- * com.ssh.service.*.*(*)第一个*表示方法返回类型为所有,
第二个*表示service包下的所有类,第三个*表示类下的所有方法,
(*)表示方法参数的个数.一个点表示一个参数,..两个点表示两个参数(*)表示任意参数-->
<aop:pointcut id="serviceOperation" expression="execution(* com.ssh.service.*.*(*))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />
</aop:config>
附上两个hibernate的util类----封装hibernate连接数据库的步骤,直接得到sesson,并且sesson只初始化一次:
HibernateUtil:
package utils;
import javax.jms.JMSException;
import javax.jms.Session;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final ThreadLocal<Session>threadLocal=new ThreadLocal<Session>();
private static SessionFactory sessionFactory=null;
static{
try{
Configuration cfg=new Configuration().configure();
sessionFactory=cfg.buildSessionFactory();
}catch(Exception e){
System.err.println("创建会话工厂失败");
e.printStackTrace();
}
}
public static Session getSession() throws HibernateException{
Session session=(Session)threadLocal.get();
if(session==null||!((org.hibernate.Session) session).isOpen()){
if(sessionFactory==null){
rebuildSessionFactory();
}
session=(Session) ((sessionFactory!=null)?sessionFactory.openSession():null);
threadLocal.set(session);
}
return session;
}
public static void rebuildSessionFactory(){
try{
Configuration cfg=new Configuration().configure();
sessionFactory=cfg.buildSessionFactory();
}catch(Exception e){
System.out.println("创建会话工厂失败");
e.printStackTrace();
}
}
public static SessionFactory getSessionFactory(){
return sessionFactory;
}
public static void closeSession() throws HibernateException, JMSException{
Session session=(Session)threadLocal.get();
threadLocal.set(null);
if(session!=null){
session.close();
}
}
}
hibernateutil:
public class HibernateUtil {
private static Configuration configuration;
private static SessionFactory sessionFactory;
static {
//只对sessionFactory初始化一次
configuration=new Configuration().configure();
sessionFactory=configuration.buildSessionFactory();
}
/**
* 获得hibernate操作对象
*/
public static Session openSession(){
return sessionFactory.openSession();
}
//服务层就不要再sessionFactory.close,关闭sessionFactory
}
又遇上问题:
Error creating bean with name 'sessionFactory' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Mapping directory location [ServletContext resource [/cn/itcast/shop/user/vo/User.hbm.xml]] does not denote a directory
正确配置: