SSH整合
1.整合思路
spring容器管理各层需要的对象
2.整合注意点
2.1.整合一个测试一个
2.2.使用框架,尽量复制
3.SSH整合的步骤
3.1.导入jar包
导入hibernate jar包
1)hibernate 框架必须的基础包
路径:E:…\SSH整合\SSH整合jar包\hibernate\hibernate-release-5.0.7.Final\lib\required
required文件夹下的所有jar包
2)补充:hibernate-entitymanager-5.0.7.Final.jar \jpa文件夹下
SUM公司推出的ORM规范 --全部都是借口。 属于数据持久化的规范技术
3)数据库驱动
注意:不管是hibernate 或者mybatis 都没有提供相应的数据库驱动;
需要连接MySQL,MySQL驱动;连接Oracle,Oracle驱动包。
导入struts2 jar包
1)struts2-blank 文件夹所有jar包
磁盘路径:E:…\SSH整合\SSH整合jar包\struts2\struts-2.3.24\apps\struts2-blank\WEB-INF\lib
特别提醒:copy时,去掉重复的jar包。 删除低版本 ,保留高版本。
2)整合Struts2 spring 的jar包
struts2-spring-plugin-2.3.24.jar
磁盘路径:E:\MyVideo\学习\IT互联网\JAVAEE\SSH体系\SSH整合\SSH整合jar包\struts2\struts-2.3.24\lib
特别提醒:如果没有配置spring ,单独启动struts2,就会去寻找spring容器,找不到就抛出异常。
导入spring jar包
1)4+2 基础包
4:spring-core ,spring-bean, spring-context, spring-express(spring的EL,表达式语言)
2:com.springsource.org.apache.commons.logging-1.1.1.jar
【路径:E:\MyVideo\学习\IT互联网\JAVAEE\SSH体系\SSH整合\SSH整合jar包\spring\spring-framework-3.0.2.RELEASE-dependencies\org.apache.commons\com.springsource.org.apache.commons.logging\1.1.1】
com.springsource.org.apache.log4j-1.2.15.jar
【路径:E:\MyVideo\学习\IT互联网\JAVAEE\SSH体系\SSH整合\SSH整合jar包\spring\spring-framework-3.0.2.RELEASE-dependencies\org.apache.log4j\com.springsource.org.apache.log4j\1.2.15】
【copy commons-logging-1.1.1.jar ,log4j-1.2.16.jar 】(最开始以为没有找的替代版本,后来网上下载到了)
- spring整合 web包
spring-web-5.1.12.RELEASE.jar
3)spring整合 AOP 4个包
官方两个包 spring-aop, spring-aspects
三方两个包 com.springsource.org.aopallience-1.0.0.jar , com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
【三方两包路径:E:\SSH体系\SSH整合\SSH整合jar包\spring\spring-framework-3.0.2.RELEASE-dependencies】
- 整合hibernate 和事务包
三个包:spring-jdbc-5.1.2.RELEASE.jar , spring-orm-5.1.2.RELEASE.jar , spring-tx-5.1.2.RELEASE.jar
5)c3p0连接池包
com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
- Junit4 测试包
spring-test-5.1.2.RELEASE.jar
- 标签库包
jstl.jar , standard.jar
总结:
搭架子的jar包总数 42个 – 需要实操,唯手熟尔。
3.2.单独配置spring框架
3.2.1.spring的配置文件
【戏称为 beans文件】可以通过模板生成
spring配置文件先不要做任何的配置,有抬头内容即可【一些约束文件及其实例】
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
</beans>
3.2.2.web.xml配置spring容器
<!-- 配置spring容器在项目启动的配置 -->
<!-- 通过快捷键CTRL+shift+t 打开ContextLoaderListener 复制而来 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
3.2.3.启动tomcat
测试spring框架已经配置完成,没有报错,就可以了。
3.3单独配置struts2框架
3.3.1.创建XxAction
创建的XxAction 需要继承 ActionSupport 示例:
package com.zl.web;
import com.opensymphony.xwork2.ActionSupport;
public class SupplierAction extends ActionSupport {
public String supplier() throws Exception {
//first 重写execute方法 super.execute();
System.out.println("SupplierAction对象创建成功");
return SUCCESS;
}
}
3.3.2.struts.xml
创建struts2的核心配置文件 struts.xml 示例:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<!-- 抬头文件struts的dtd,不要记忆,靠复制 -->
<struts>
<package name="zl" namespace="/" extends="struts-default">
<action name="supplierAction" class="com.zl.web.SupplierAction"
method="supplier">
<result name="success">/supplier.jsp</result>
</action>
</package>
</struts>
3.3.3.web.xml配置struts核心过滤器
3.3…4.启动tomcat测试
配置struts2的debug
代码没有问题,前端页面报找不到XxAction类的异常;
考虑编译环境的问题:
struts2 需要tomcat8.0以上,jdk8的环境。
3.4 spring-struts2整合
spring配置XxAction
将原来由Struts2负责创建的XxAction交给Spring容器。
<!-- 让struts2种的action交给spring容器来管理 -->
<bean name="supplierAction" class="com.zl.web.SupplierAction">
<property name="supplierService" ref="supplierService"></property>
</bean>
修改struts.xml
<struts>
<package name="zl" namespace="/" extends="struts-default">
<!-- class类属性修改为spring里面的beanName,完成引用 -->
<!-- class属性可以是创建实例的类,又或者是spring容器里面的beanName -->
<action name="supplierAction" class="supplierAction"
method="supplier">
<result name="success">/supplier.jsp</result>
</action>
</package>
</struts>
3.4.3.启动tomcat
特别注意:
struts2的设计理念是【多例】,spring默认【单例】,因此整合时需要更改<scope>为prototype
整合过程的debug:
解决:
先把Tomcat停掉 , 然后选Eclipse导航栏的Project > Clean , clean会删除项目WebRoot下的classes文件 , 然后自动重新编译再生成class文件。
最优解决:
先把Tomcat停掉 , 然后选Eclipse导航栏的 Project->Build Aotumatically ,打上勾可以了,完成自动重建。
3.5单配hibernate框架
1)导入jar包
相关jar包,第一步已做。
2)添加配置文件
hibernate核心配置文件
提供示例模板:hibernate.cfg.xml 只能叫这个名字,hibernate框架才会自动读取
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!--数据库驱动-->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!--连接数据库URL--><!--通过URL解决hibernate向MySQL插入中文乱码问题-->
<property name="connection.url">
<![CDATA[jdbc:mysql://192.168.200.150:3306/zl_orm?useUnicode=true&characterEncoding=utf8]]></property>
<!--连接数据库的用户名-->
<property name="connection.username">root</property>
<!--数据库用户密码-->
<property name="connection.password">root</property>
<!--选择数据库使用的方言-->
<!-- hibernate dialect org.hibernate.dialect.MySQLDialect 对应 MySQL5.0之前 -->
<!--<property name="dialect">org.hibernate.dialect.MySQLDialect</property>-->
<!-- dialect org.hibernate.dialect.MySQL5InnoDBDialect 对应MySQL5.0版本之后-->
<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<!-- 连接池的配置 -->
<!--JDBC连接池最大连接数-->
<property name="hibernate.c3p0.max_size">20</property>
<!--JDBC连接池最小连接数-->
<property name="hibernate.c3p0.min_size">1</property>
<!--连接池连接的超时时间-->
<property name="hibernate.c3p0.timeout">5000</property>
<!--连接池最大缓存多少个statement对象-->
<property name="hibernate.c3p0.max_statements">100</property>
<!--每隔3000秒检查连接池里的空闲连接-->
<property name="hibernate.c3p0.idle_test_period">3000</property>
<!--连接池里面的连接用完的时候,指定c3p0可以获取2个新的连接数-->
<property name="hibernate.c3p0.acquire_increment">2</property>
<!--每次验证连接池的连接是否可用-->
<property name="hibernate.c3p0.validate">true</property>
<!--JDBC连接池(使用内置的连接池)-->
<property name="connection.pool_size">1</property>
<!--根据需要自动创建数据表--> <!--在启动时删除并重新创建数据库-->
<property name="hbm2ddl.auto">update</property>
<!--显示执行的SQL语句-->
<property name="show_sql">true</property>
<!--将sql脚本进行格式化后输出-->
<property name="hibernate.format_sql">true</property>
<!--设置Hibernate自动管理上下文的策略-->
<!--<property name="current_session_context_class">thread</property>-->
<!--下面罗列出持久化类的类名--><!--类的全限定名-->
<mapping class="com.zl.hibernate.po.User"/>
</session-factory>
</hibernate-configuration>
-
pojo
package com.zl.domain;
import java.util.Date;
public class User {
private Integer id; private String username; private Date birthday; //java.util.Date; private String sex; private String address; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", date=" + birthday + ", sex=" + sex + ", address=" + address + "]"; }
}
细节
实体类的date,与数据库的date数据交互。
因为,数据库的date是“yyyy-MM-dd”的形式,因此实体类的date,也需要借助简单日期转换器转换为“yyyy-MM-dd”
再hibernate的配置文件中五大参数可以省略前缀【hibernate】,但是如果是在spring文件中五大参数必须有【hibernate】;并且,spring文件中的hibernate配置,去五大参数的【key】应该是固定
示例:
//Java Date 对应jdbc的date类型 StringDate -> Date
String pattern = "yyyy-MM-dd";
String sDate = "1997-10-01";
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
Date date = sdf.parse(sDate);
hibernate的debug
我最大的错误就是不去找错误日志;借助错误日志,完成排查,成功测试。
bug1:
log4j缺少log4j2.xml配置文件,error报错 ~~网上找个模板,解决
bug2:
太自信了,不信息自己配置文件有错误,有了第一步,再加上调试,得到无效的hibernate配置文件
排查后得到是,注释时 【 --> 】不合法
bug3:
类表之间的“数据交换”都是通过类属性的getter/setter方法完成,一定一定一定要确保 get/set后面跟属性名。
hibernate-orm映射文件
提供示例: 映射文件名【EntityName+hbm.xml】, 实体类名字+.hbm.xml
提醒:hibernate-orm映射文件最好与实体类放到一块【并非强制】
<?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">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
hibernate的映射文件名称 命名规则为 “类名.hbm.xml”
-->
<hibernate-mapping>
<!--实体类的类全名-->
<class name="com.zl.hibernate.po.User">
<!--属性/成员变量 与 表的主键映射-->
<id name="id" column="id">
<generator class="increment"></generator>
</id>
<!--其他属性/成员变量 与 表的字段映射-->
<property name="username" column="username" type="java.lang.String" length="20"></property>
<property name="birthday" column="birthday" type="java.util.Date" length="20"></property>
<property name="sex" column="sex" type="java.lang.String" length="20"></property>
<property name="address" column="address" type="java.lang.String" length="20"></property>
</class>
</hibernate-mapping>
3)测试hibernate框架
测试使用的表 user
测试使用的entity:
@Data
public class User {
//成员变量
private Integer id;
private String username;
private Date birthday;//java.util.Date;
private String sex;
private String address;
}
3.6 spring-hibernate整合
1)spring引入hibernate
spring的核心文件引入hibernate文件
<!-- sessionFactory交给spring容器管理 【事实上是其实现子类LocalSessionFactory交给spring容器】 -->
<!--
整合hiberna框架,将LocalSessionFactoryBean交给spring容器管理
sessionfactory 的实现子类
-->
<!-- 配置方式1 直接加载hibernate的配置文件 -->
<bean name="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- 需要告诉LocalSessionFactoryBean 去哪里读取hibernate文件 ,靠下面的属性 -->
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
</bean>
<!-- 配置方式2 hibernate文件的所有配置都写在spring的配置文件中 -->
<!-- 方法二,重点掌握 目标hibernate的所有配置都写进spring配置文件beans中 -->
<!-- 先来五个必选参数压压惊 -->
<!-- 接收复杂参数的固定形式,这里接受Map类型的多个 “key-value对” -->
<bean name="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="hibernateProperties">
<!-- 5个必选参数 -->
<!-- 2个可选参数 -->
<props>
<prop key="hibernate.connection.driver_class">com.mysql.jdbc.Driver</prop>
<prop key="hibernate.connection.url"><![CDATA[jdbc:mysql://192.168.200.150:3306/zl_orm?useUnicode=true&characterEncoding=utf8]]></prop>
<prop key="hibernate.connection.username">root</prop>
<prop key="hibernate.connection.password">root</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
<!-- 让spring去哪里加载ORM映射文件 -->
<!-- 包扫描 ,可以读取到包下的所有配置文件-->
<property name="mappingDirectoryLocations" value="classpath:com/zl/domain"></property>
</bean>
spring-hibernate整合debug
版本不一致:
spring版本 与 hibernate版本不一致
org.springframework.orm.hibernate5.LocalSessionFactoryBean 对应 hibernate5
配置文件错误:
spring文件引入hibernate部分的 bean 属性配置错误;
configLocation 误写为 [configLocations] 或者 不是LocalSessionFactoryBean的属性(就没有get/set方法);
"classpath:hibernate.cfg.xml" 少写了 前面的[classpath:] ;
错误提示信息:
Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property 'configLoca' of bean class [org.springframework.orm.hibernate5.LocalSessionFactoryBean]: Bean property 'configLoca' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
明确告诉我们,configLoca这个属性在LocalSessionFactoryBean没有找到,就不能找到setter方法注入。
方式二 包扫描【路径分隔符号】错误:
com.zl.domain
<property name="mappingDirectoryLocations" value="classpath:com.zl.domain"></property>
错误提示信息:
Caused by: java.io.FileNotFoundException: class path resource [com.zl.domain] cannot be resolved to
com.zl.domain ---> 改为:com/zl/domain 解决。
3.7 spring-其他
3.7.1.c3p0
1)数据源 bean 交付spring创建
数据源可以是c3p0 也可以是德鲁伊连接池。 此处选择c3p0
<!-- c3p0交付spring创建 -->
<!-- 注意键是ComboPooledDataSource属性名字 -->
<!-- springDTDT约束文件规定 URL多参数之间需要使用【&】分隔 -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://192.168.200.150:3306/zl_orm?useUnicode=true&characterEncoding=utf8"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
</bean>
-
spring创建c3p0 debug
配置文件xml:
转义字符问题:
提示信息:
对实体 “characterEncoding” 的引用必须以 ‘;’ 分隔符结尾
解决:URL拼接参数时,使用 【&】
jdbc:mysql://192.168.200.150:3306/zl_orm?useUnicode=true;characterEncoding=utf8 替换为
jdbc:mysql://192.168.200.150:3306/zl_orm?useUnicode=true&characterEncoding=utf8 -
创建c3p0优化
开发中,数据源一般有三个;线上,本地开发以及测试
属于变化比较频繁,因此可以将其提取到配置文件,后面要换数据源只需要修改配置文件。
创建 db.properties
driverClass=com.mysql.jdbc.DriverjdbcUrl=jdbc:mysql://192.168.200.150:3306/zl_orm?useUnicode=true&characterEncoding=utf8user=rootpassword=root
读取外部文件db,properties ,再使用spring的取值表达式,取值
<!-- 注意键是ComboPooledDataSource属性名字 -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${driverClass}"></property>
<property name="jdbcUrl" value="${jdbcUrl}"></property>
<property name="user" value="${user}"></property>
<property name="password" value="${password}"></property>
</bean>
-
c3p0优化bug
优化时:遇到中文乱码的问题,有对编码设置 utf-8,未生效;
查看,原来properties文件,&characterEncoding的引用,前面只需要加 【&】 。
3.7.2.事务
1)spring创建【事务】
<!-- 配置事务通知 -->
<tx:advice id="txadvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="find*" isolation="READ_COMMITTED" propagation="REQUIRED" read-only="true"/>
<tx:method name="add*" isolation="READ_COMMITTED" propagation="REQUIRED" read-only="false"/>
</tx:attributes>
</tx:advice>
<!-- 配置AOP织入 -->
<aop:config>
<!-- 切点表达式 -->
<aop:pointcut expression="execution(* com.zl.service.*Service.*(..))" id="pc"/>
<aop:advisor advice-ref="txadvice" pointcut-ref="pc"/>
</aop:config>
-
创建事务过程 debug
给service层创建事务,却忘记注入dao层到service层;
报错提示信息:
java.lang.NullPointerException
at com.zl.service.UserService.addUser(UserService.java:48)
调用addUser()方法时,报空指针,因为 真正执行的UserDao 没有注入到service,因此未默认值null;
超级坑点,再事务配置无误的情况下
报错提示信息:
org.springframework.transaction.CannotCreateTransactionException: ![Could not open Hibernate Session for transaction; nested exception is java.lang.BootstrapMethodError:]! java.lang.NoClassDefFoundError: org/hibernate/engine/spi/SharedSessionContractImplementor
两种解决方案:
1)修改事务通知范围 propagation属性 [REQUIRED]
<tx:method name="find*" isolation="READ_COMMITTED" propagation="REQUIRED" read-only="true"/><tx:method name="add*" isolation="READ_COMMITTED" propagation="REQUIRED" read-only="false"/>
更改为: [SUPPORTS]
<tx:method name="find*" isolation="READ_COMMITTED" propagation="SUPPORTS" read-only="true"/>
<tx:method name="add*" isolation="READ_COMMITTED" propagation="SUPPORTS" read-only="false"/>
2) 更换spring的jar包 spring-aspects-5.1.2.RELEASE.jar
更换为: 4.2.4.RELEASE 说明开发还是以稳定为主,学习可以尝试新版。
4.SH结合操作数据库
SH指的是:spring整合hibernate之后,操作数据库
4.1核心类
使用的核心类是 hibernatetemplate 与 hibernateDaoSupport
两者的不同点: hibernatetemplate需要在使用类,创建变量ht来注入; hibernateDaoSupport则并不需要,只需要XXDao实用类继承。 举例子: public class UserDao 【extends】 HibernateDaoSupport
-查询(查询返回当个对象,查询返回list)
-添加
4.2 XXdao由spring创建
如果我们采用XXDao 继承 HibernateDaoSupport的方式,就必须要在创建XXDao bean,给bean属性注入sessionfactory当然是 HibernateDaoSupport 需要依赖 sessionfactory 。通过子类继承的属性注入值,传递给父类。
<!-- 示例 -->
<!-- spring容器管理dao层 -->
<bean name="userDao" class="com.zl.dao.UserDao">
<!-- 子类userDao给继承来的属性sessionFactory,注入bean,传递给父类HibernateDaoSupport,这是父类必 须要有的依赖" -->
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
4.3 debug
规范问题:
定义的方法,如果不是给属性赋值/取值,尽量避开 getXx/setXx方法命令方式。
XxDao bean配置:
缺少sessionfactory
提示信息:
Caused by: java.lang.IllegalArgumentException: 'sessionFactory' or 'hibernateTemplate' is required;
java.lang.IllegalArgumentException,这类异常,一般是属性赋值错误或者缺少必要属性;
解决:加上sessionFactory属性
<property name="sessionFactory" ref="sessionFactory"></property>
4.4 操作方法
有四种查询方式:
方式1 session
方式2 HQL
方式3 SQL
方式4 criteria 面向对象
本示例展示方式2 & 方式4
/**
* 根据用户ID获取用户
*/
public User findUser(final Integer id) {//语法要求,匿名内部类,拿到外部的参数,必须加上final修饰
//方式2 QHL
User user=getHibernateTemplate().execute(new HibernateCallback<User>() {//链式编程.execute方法,接受匿名内部类
@Override
public User doInHibernate(Session session) throws HibernateException {
//1.编写hql语句
String hql = "from com.zl.domain.User where id=?";
Query query = session.createQuery(hql);
query.setParameter(0, id);
User user = (User) query.uniqueResult();
return user;
}
});
return user;
}
/**
* 根据用户IDS获取用户的list集合
* 使用方式4 criteria 标准entity方式
* @return
*/
public List<User> findUsers(){//规范,只有属性/变量才使用get/set方法,其它方法不要使用
// 方式4 criteria
DetachedCriteria dcriteria = DetachedCriteria.forClass(User.class);
//有getHibernateTemplate,必然有setHibernateTemplate(),并且注入hibernateTemolate必须有sessionfactory;
List<User> list = (List<User>) getHibernateTemplate().findByCriteria(dcriteria);
//只要是查询必须判断是否为空 ,规范
if (list!=null&&list.size()>0) {
//list.forEach(e->{System.out.println(e);});
return list;
}else {
return null;
}
}
}
4.5 更多操作方法
增加entity
/** * 添加用户信息 * @throws ParseException */ public void addUser() throws ParseException { User user = new User(); user.setUsername("牛魔王"); user.setSex("男"); //Java Date 对应jdbc的date类型 StringDate -> Date String pattern = "yyyy-MM-dd"; String sDate = "1997-10-01"; SimpleDateFormat sdf = new SimpleDateFormat(pattern); Date date = sdf.parse(sDate); user.setBirthday(date); user.setAddress("莫锡国"); getHibernateTemplate().save(user); }
报错了
报错提示信息:
org.springframework.dao.InvalidDataAccessApiUsageException: 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.
这是告诉我们,这是只读模式,查询没问题,增删改就需要修改为可读可写,增加事务。
SSH整合最终版配置
spring.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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!-- 读取外部配置文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- c3p0交付spring创建 -->
<!-- 注意键是ComboPooledDataSource属性名字 -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${driverClass}"></property>
<property name="jdbcUrl" value="${jdbcUrl}"></property>
<property name="user" value="${user}"></property>
<property name="password" value="${password}"></property>
</bean>
<!-- 让struts2种的action交给spring容器来管理 -->
<bean name="supplierAction" class="com.zl.web.SupplierAction" scope="prototype">
<property name="supplierService" ref="supplierService"></property>
</bean>
<!-- 让service层交给spring容器管理 -->
<bean name="supplierService" class="com.zl.service.SupplierService"></bean>
<bean name="userService" class="com.zl.service.UserService">
<!-- 将XxDao注入到service层 -->
<property name="userDao" ref="userDao"></property>
</bean>
<!--
整合hiberna框架的东西:
核心配置文件
orm映射文件
将LocalSessionFactoryBean交给spring容器管理 (LocalSessionFactoryBean) sessionfactory 的实现子类
创建 sessionfactory的过程中,会主动与数据库链接。如果没有开启数据库,找不到会报错。
-->
<!-- 方法一,但是不推荐 -->
<!-- 需要告诉LocalSessionFactoryBean 去哪里读取hibernate文件 ,靠下面的属性 -->
<!--
<bean name="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
</bean>
-->
<!-- 方法二,重点掌握 目标hibernate的所有配置都写进spring配置文件beans中 -->
<!-- 先来五个必选参数压压惊 -->
<!-- 接收复杂参数的固定形式,这里接受Map类型的多个 “key-value对” -->
<bean name="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<!-- c3p0 注入到hibernate框架 -->
<property name="dataSource" ref="dataSource"></property>
<property name="hibernateProperties">
<!-- 5个必选参数 -->
<!-- 2个可选参数 -->
<props>
<!-- c3p0连接池就能提供了
<prop key="hibernate.connection.driver_class">com.mysql.jdbc.Driver</prop>
<prop key="hibernate.connection.url"><![CDATA[jdbc:mysql://192.168.200.150:3306/zl_orm?useUnicode=true&characterEncoding=utf8]]></prop>
<prop key="hibernate.connection.username">root</prop>
<prop key="hibernate.connection.password">root</prop>
-->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
<!-- 让spring去哪里加载ORM映射文件 -->
<!-- 包扫描 ,可以读取到包下的所有配置文件-->
<property name="mappingDirectoryLocations" value="classpath:com/zl/domain"></property>
</bean>
<!-- spring容器管理dao层 -->
<bean name="userDao" class="com.zl.dao.UserDao">
<!-- 子类userDao给继承来的属性sessionFactory,注入bean,传递给父类HibernateDaoSupport,这是父类必须要有的依赖" -->
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- spring容器管理事务 -->
<!-- 打开 Ctrl + shift + T 搜索HibernateTransactionManager -->
<bean name="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<!-- 依赖sessionfactory 属性注入 -->
<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="find*" isolation="READ_COMMITTED" propagation="SUPPORTS" read-only="true"/>
<tx:method name="add*" isolation="READ_COMMITTED" propagation="SUPPORTS" read-only="false"/>
</tx:attributes>
</tx:advice>
<!-- 配置AOP织入 -->
<aop:config>
<!-- 切点表达式 -->
<aop:pointcut expression="execution(* com.zl.service.*Service.*(..))" id="pc"/>
<aop:advisor advice-ref="txadvice" pointcut-ref="pc"/>
</aop:config>
</beans>
spring扩展
spring实体类复杂属性注入
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!-- 以下内容,与SSH整合项目无关 借助搭好的架子做测试用的bean -->
<!-- 测试给实体类复杂属性复制 -->
<bean name="beanComplexTypeDI" class="com.zl.test.BeanComplexTypeDI">
<property name="myString" value="这是我的测试"> </property>
<property name="myPojo" ref="myPojo"></property>
<!-- 复杂类型之数组 -->
<property name="myArray">
<array>
<value>这是数组数据注入</value>
</array>
</property>
<property name="myList">
<list>
<ref bean="myPojo"/>
</list>
</property>
<property name="mySet">
<set>
<ref bean="myPojo"/>
</set>
</property>
<property name="myMap">
<map>
<entry key="map001" value-ref="myPojo"></entry>
</map>
</property>
<property name="myProperties">
<props>
<prop key="prop">复杂类型属性数据注入</prop>
</props>
</property>
</bean>
<bean name="myPojo" class="com.zl.test.MyPojo">
<property name="name" value="这是我测试用的pojo"></property>
</bean>
</beans>
struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package name="zl" namespace="/" extends="struts-default">
<action name="supplierAction" class="supplierAction"
method="supplier">
<result name="success">/supplier.jsp</result>
</action>
</package>
</struts>
hibernate.cfg.xml
这里面的配置已经全部放到spring bean。做参考
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!--数据库驱动-->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!--连接数据库URL--><!--通过URL解决hibernate向MySQL插入中文乱码问题-->
<property name="connection.url">
<![CDATA[jdbc:mysql://192.168.200.150:3306/zl_orm?useUnicode=true&characterEncoding=utf8]]></property>
<!--连接数据库的用户名-->
<property name="connection.username">root</property>
<!--数据库用户密码-->
<property name="connection.password">root</property>
<!--选择数据库使用的方言-->
<!-- hibernate dialect org.hibernate.dialect.MySQLDialect 对应 MySQL5.0之前 -->
<!-- <property name="dialect">org.hibernate.dialect.MySQLDialect</property> -->
<!-- dialect org.hibernate.dialect.MySQL5InnoDBDialect 对应MySQL5.0版本之后-->
<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<!-- 连接池的配置 -->
<!--JDBC连接池最大连接数-->
<property name="hibernate.c3p0.max_size">20</property>
<!--JDBC连接池最小连接数-->
<property name="hibernate.c3p0.min_size">1</property>
<!--连接池连接的超时时间-->
<property name="hibernate.c3p0.timeout">5000</property>
<!--连接池最大缓存多少个statement对象-->
<property name="hibernate.c3p0.max_statements">100</property>
<!--每隔3000秒检查连接池里的空闲连接-->
<property name="hibernate.c3p0.idle_test_period">3000</property>
<!--连接池里面的连接用完的时候,指定c3p0可以获取2个新的连接数-->
<property name="hibernate.c3p0.acquire_increment">2</property>
<!--每次验证连接池的连接是否可用-->
<property name="hibernate.c3p0.validate">true</property>
<!--JDBC连接池(使用内置的连接池)-->
<property name="connection.pool_size">1</property>
<!--根据需要自动创建数据表--> <!--在启动时删除并重新创建数据库-->
<!-- <property name="hbm2ddl.auto">update</property> -->
<!--显示执行的SQL语句-->
<property name="hibernate.show_sql">true</property>
<!--将sql脚本进行格式化后输出-->
<property name="hibernate.format_sql">true</property>
<!--设置Hibernate自动管理上下文的策略-->
<!--<property name="current_session_context_class">thread</property>-->
<!--下面罗列出持久化类的类名--><!--类的全限定名-->
<!-- <mapping class="com.zl.domain.User"/> -->
<!-- 把mapping映射文件引入到hibernate核心配置文件 -->
<mapping resource="com/zl/domain/User.hbm.xml"></mapping>
</session-factory>
</hibernate-configuration>
db.properties
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://192.168.200.150:3306/zl_orm?useUnicode=true&characterEncoding=utf8
user=root
password=root
记录一下db.properties的小bug
当对文件做了修改后(比如同文件切换到Oracle链接参数),表面看没问题,但是通过el ${} 读取就是不能连接到数据库。
解决方法:
1)亲自测试有效,原文件复制一份数据,删掉文件,新建文件。spring.xml读取db新文件。
log4j2.xml
日志也是必不可少;bug常用,日志提供很大帮助
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
</Console>
<RollingFile name="RollingFile" fileName="logs/strutslog1.log"
filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout>
<Pattern>%d{MM-dd-yyyy} %p %c{1.} [%t] -%M-%L- %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="1 KB"/>
</Policies>
<DefaultRolloverStrategy fileIndex="max" max="2"/>
</RollingFile>
</Appenders>
<Loggers>
<Logger name="com.opensymphony.xwork2" level="WAN"/>
<Logger name="org.apache.struts2" level="WAN"/>
<Root level="warn">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>