就像奶茶大续杯一样,让我们继续和Hibernate打交道,捧好温热的奶茶在这个寒冬里,继续Hibernate的学习。
1、我们的配置hibernate.cfg.xml文件的主要作用就是创建一个sessionFactory,其会通过property配置一些数据库的连接,
也会配置Hibernate的相关属性比如方言、自动创建表机制、格式化sql等,还有就是持久化类的所在路径。
当只是用Hibernate的时候主要是用Hibernate从配置文件里获取sessionFactory,再从sessionFactory中取session,再用session对持久化对象进行操作。
2、hibernate默认加载就是名为hibernate.cfg.xml的配置文件,这是在源代码里面的
public Configuration configure() throws HibernateException {
//1.StandardServiceRegistryBuilder.DEFAULT_CFG_RESOURCE_NAME的值是"hibernate.cfg.xml"
return configure( StandardServiceRegistryBuilder.DEFAULT_CFG_RESOURCE_NAME );
}
3、配置SeesionFactory的方式有两种,一种是通过DataSource来配置sessionFactory,另一种是通过Hibernate.cxg.xml来配置。通过DataSource的方法,是Datasource数据源是注入给sessionfactory的SessionFactory是基于dataSource上建立的。
4、在单独使用hibernate的方法时,我们应该这样做
- a、配置好applicationContext.xml一般放在对应的Service的实现包下xxx\src\main\resources\applicationContext.xml
-
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd"> <!-- 用于持有ApplicationContext,可以使用SpringContextHolder.getBean('xxxx')的静态方法得到spring bean对象 该工具类主要用于:那些没有归入spring框架管理的类却要调用spring容器中的bean提供的工具类。 在spring中要通过IOC依赖注入来取得对应的对象,但是该类通过实现ApplicationContextAware接口, 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候中取出ApplicaitonContext. --> <bean id="springContextHolder" class="com.mp.jdbc.context.SpringContextHolder" lazy-init="false"/> <!-- 扫描路径不扫描controller 如果某个类的头上带有特定的注解@Component,@Repository,@Service,@Controller,就会将这个对象作为Bean注册进Spring容器。 启用了对类包进行扫描以实施注释驱动 Bean 定义的功能,同时还启用了注释驱动自动注入的功能 --> <context:component-scan base-package="com.test"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 自动注入properties文件中 DecryptPropertyPlaceholderConfigurer在加载上下文的时候,可以在XML配置文件中加入外部属性文件并加密, 当然也可以指定外部文件的编码 location指向配置文件的位置 设置为lazy的bean将不会在ApplicationContext启动时提前被实例化,而是第一次向容器通过getBean索取bean时实例化的。--> <bean id="propertyConfigurer" class="com.mp.jdbc.config.DecryptPropertyPlaceholderConfigurer" p:location="classpath:jdbc.properties" lazy-init="true"/> <!-- 配置Hibernate事务管理器 --> <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <!--datasource数据源是注入给sessionfactory的SessionFactory是基于dataSource上建立的--> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan"> <list> <!-- 可以加多个包 --> <value>com.test.entity</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</prop> <prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate5.SpringSessionContext</prop> <prop key="hibernate.show_sql">false</prop> <prop key="hibernate.format_sql">true</prop> </props> </property> </bean> <!-- 配置数据源 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" p:driverClassName="${master.driverClass}" p:url="${master.jdbcUrl}" p:username="${master.user}" p:password="${master.password}" p:initialSize="${master.initialPoolSize}" p:minIdle="${master.minPoolSize}" p:maxActive="${master.maxPoolSize}" p:maxWait="${master.maxWait}" p:timeBetweenEvictionRunsMillis="${master.timeBetweenEvictionRunsMillis}" p:minEvictableIdleTimeMillis="${master.minEvictableIdleTimeMillis}" p:validationQuery="${master.validationQuery}" p:testWhileIdle="${master.testWhileIdle}" p:testOnBorrow="${master.testOnBorrow}" p:testOnReturn="${master.testOnReturn}" p:poolPreparedStatements="${master.poolPreparedStatements}" p:maxPoolPreparedStatementPerConnectionSize="${master.maxPoolPreparedStatementPerConnectionSize}"/> <!-- 配置Hibernate事务管理器 --> <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <!-- 配置事务异常封装 --> <bean id="persistenceExceptionTranslationPostProcessor" class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="insert*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="delete*" propagation="REQUIRED"/> <tx:method name="select*" read-only="true"/> <tx:method name="*" rollback-for="java.lang.Exception" timeout="10" /> </tx:attributes> </tx:advice> <!-- 通过aop定义事务增强切面 --> <aop:config> <aop:pointcut expression="execution(* com.test.dao.impl.*.*(..))" id="txPointCut"/> <!-- 引用事务增强 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/> </aop:config> </beans>
b、配置jdbc.properties
jdbc.master=master master.key=21231312 master.driverClass=com.mysql.jdbc.Driver #master.jdbcUrl=120.0.0.1 #root 填你自己的账号,密码,这里的属性配置只是换了一种形式,之后会通过spring读取到 master.user=test master.password=test master.filters=stat master.initialPoolSize=5 master.minPoolSize=5 master.maxPoolSize=15 master.maxWait=20000 master.timeBetweenEvictionRunsMillis=60000 master.minEvictableIdleTimeMillis=300000 master.validationQuery=SELECT 1 master.testWhileIdle=true master.testOnBorrow=false master.testOnReturn=false master.poolPreparedStatements=false master.maxPoolPreparedStatementPerConnectionSize=200
c、根据自己的实际情况来,在生成的实体类上打上注解,@Column这个注解有些属性
@Target({ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface Column { //被标注字段在数据库表中所对应字段的名称 String name() default ""; //表示该字段是否为唯一标识,默认为false。同@Table标记中的@UniqueConstraint boolean unique() default false; //该字段是否可以为null值,默认为true boolean nullable() default true; //在使用“INSERT”脚本插入数据时,是否需要插入该字段的值,一般多用于只读的属性 boolean insertable() default true; //在使用“UPDATE”脚本插入数据时,是否需要更新该字段的值,一般多用于只读的属性 boolean updatable() default true; //创建表时,该字段创建的SQL语句,一般用于通过Entity生成表定义时使用,但DB中表已经建好就可不用 String columnDefinition() default ""; //定义了包含当前字段的表名 String table() default ""; //字段的长度,当字段的类型为varchar时,该属性才有效 int length() default 255; //表示精度,当字段类型为double时,precision表示数值的总长度,scale表示小数点所占的位数。 int precision() default 0; int scale() default 0; }
d、为你操作的持久类设置值,这个操作一般都在Service层中
XXXPO xxxPO = new XXXPO(); xxxPO.setCompanyId(companyId); xxxPO.setType(type); xxxPO.setCreateTime(DateTimeHelper.long2TimeStamp(System.currentTimeMillis())); XXXDao.insertRedPoint(redPoint);
e、在DAO层使用@Repository 和@Resource注解和对应的语句进行持久化操作,以下列举了多种的Hibernate查询的方法
/*当Service需要使用Spring创建的名字叫“XXXXDao”的XXXXDaoImpl实例时, 就可以使用@Resource(name = "userDao")注解告诉Spring, Spring把创建好的userDao注入给Service即可。 注解在持久层中,具有将数据库操作抛出的原生异常翻译转化为spring的持久层异常的功能 */ @Repository public class XXXXDaoImpl extends AbstractDao implementsXXXXDao { private static final Logger logger = LoggerFactory.getLogger(XXXXDaoImpl.class); @Resource 用来装配bean private SessionFactory sessionFactory; private Session getSession() { return sessionFactory.getCurrentSession(); } private Connection conn; public XXXXDaoImpl() { } public XXXXDaoImpl(Connection con) { this.conn = con; } @Override public void updateCheckCount(Integer announcementId) throws SQLException { /** * 对象查询(Query By Criteria) * 1、CriteriaBuilder可以用于创建CriteriaQuery、CriteriaUpdate和CriteriaDelete。 * 除此之外类似count、max等函数也是由CriteriaBuilder来创建的 * 2、调用criteriaBuilder.createQuery来创建CriteriaQuery。 * 其中createQuery的参数是Query返回值类型 * 3、调用query.from(Order.class),参数是对应于数据库里表的实体类, * query.from类似于sql中的from语句,该方法的执行等价于sql中的from order。 * 4、调用 query.select创建映射,query.select(criteriaBuilder.count(root.get(“id”)))等价于select count(id)。 * 如果执行query.select(root)则等价于select *。 * 5、使用CriteriaBuilder构造查询条件Predicate,该predicate也就是在where后面的条件子句。 * 6、getSession().createQuery(criteriaQuery).uniqueResultOptional()最后执行查询获取数据 */ CriteriaBuilder builder = getSession().getCriteriaBuilder(); CriteriaQuery<XXXXPO> criteriaQuery = builder.createQueryXXXXPO.class); Root<AnnouncementPO> root = criteriaQuery.from(AnnouncementPO.class); criteriaQuery.select(root); criteriaQuery.where(builder.equal(root.get("id"), announcementId)); Optional<XXXXPO> xxxxPO = getSession().createQuery(criteriaQuery).uniqueResultOptional(); //如果Optional实例有值则将其返回,否则返回orElse方法传入的参数 XxxxPO xxxx = announcementPO.orElse(null); getSession().save(announcement); }
/** 1、主键查询的方法有两种方法:get()和load()支持懒加载 */ User u = (User) session.get(User.class, 1); User u = (User) session.load(User.class, 1); /** * 2、HRL查询,查询全部信息,支持方法链的编程,即直接调用list()方法 * 注意HRL查询的是实体类的名称,不是数据表的名称,特别注意这一点 */ //2.1查询所有 会得到list集合 Query q=session.createQuery("from User"); //2.2 条件查询 (包括正序asc倒序desc)如下 Query query = session.createQuery("from Good where gname = ? and gmono =?"); query.setParameter(0, "面包"); query.setParameter(1, "奶油面包"); List<Good> list = query.list(); //2.3 分页查询 Query query = session.createQuery("from Good"); //2.3.1设置第一个要查询的位置(计算公式:(当前页数-1)*每页的记录数) query.setFirstResult(0); //2.3.2设置每页显示的最大记录数 query.setMaxResults(3); // 2.3.3使用Query对象的list方法得到数据集合 List<Good> list = query.list(); //2.4聚集函数查询 Query query = session.createQuery("select count(*) from Good"); Object obj = query.uniqueResult();//获取结果(结果为long类型) Long long1 = (Long) obj;//转化为long(类型为long,转为int会报错) int count = long1.intValue(); /** *2.5多表查询和sql语法一样 * 内连接查询 * 显示内连接 * select * from customers c inner join orders o on c.cid = o.cno; * 隐式内连接 * select * from customers c,orders o where c.cid = o.cno; * 外连接查询 * 左外连接 * select * from customers c left join orders o on c.cid = o.cno; * 右外连接 * select * from customers c right join orders o on c.cid = o.cno; */ /** 3、完全的面向对象的查询 */ //3.1. 简单查询,使用的是Criteria接口 List<Customer> list = session.createCriteria(Customer.class).list(); //3.2 排序查询 Criteria criteria = session.createCriteria(Linkman.class); criteria.addOrder(Order.desc("id")); List<Linkman> list = criteria.list(); //3.3分页查询 Criteria criteria = session.createCriteria(Linkman.class); criteria.addOrder(Order.desc("lkm_id")); criteria.setFirstResult(0); criteria.setMaxResults(3); List<Linkman> list = criteria.list(); /**3.4条件查询 * 条件查询使用Criteria接口的add方法,用来传入条件。 * 使用Restrictions的添加条件的方法,来添加条件,例如: * Restrictions.eq -- 相等 * Restrictions.gt -- 大于号 * Restrictions.ge -- 大于等于 * Restrictions.lt -- 小于 * Restrictions.le -- 小于等于 * Restrictions.between -- 在之间 * Restrictions.like -- 模糊查询 * Restrictions.in -- 范围 * Restrictions.and -- 并且 * Restrictions.or -- 或者 */ Criteria criteria = session.createCriteria(User.class); //a、添加条件 criteria.add(Restrictions.eq("id", 1)); //查询全部,没有sql语句 List<User> list = criteria.list(); //b、多条件 Criteria criteria = session.createCriteria(Linkman.class); // 设置排序 criteria.addOrder(Order.desc("lkm_id")); // 设置查询条件 criteria.add(Restrictions.or(Restrictions.eq("lkm_gender", "男"), Restrictions.gt("lkm_id", 3L))); List<Linkman> list = criteria.list(); /** * 3.5 聚合条件查询 criteria.setProjection() */ Criteria criteria = session.createCriteria(Linkman.class); criteria.setProjection(Projections.rowCount()); List<Number> list = criteria.list(); Long count = list.get(0).longValue(); System.out.println(count); /** * 4、本地查询sql语句,适合使用复杂的查询, 或者不想使用HQL或者criteria查询,可以使用本地sql查询 */ //sql语句 SQLQuery sql = session.createSQLQuery("select * from user "); SQLQuery sql = session.createSQLQuery("select * from user where id=1 "); sql.addEntity(User.class); List<User> list = sql.list(); System.out.println(list); String sql = "UPDATE USER SET NAME = ? WHERE id =1"; getSession().createSQLQuery(sql).setParameter(1, id).executeUpdate();
小猴,在这边提醒如果只是使用hibernate的话,又想要spring托管,就要在初始化的时候让其起到作用
-
new ClassPathXmlApplicationContext("applicationContext.xml");