SSH框架笔记之(Hibenate问题篇)

单独使用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&amp;characterEncoding=utf8&amp;serverTimezone=GMT%2B8&amp;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
	

正确配置:

猜你喜欢

转载自blog.csdn.net/qq_41063141/article/details/88636807