断断续续学习hibernate也有一段时间了,在这里研究一下SSH开发环境的搭建过程,自己简单的搭建一个SSH的开发环境。采用maven搭建。
0.项目结构:
1.导包:(maven项目)
pom.xml配置文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cn.qlq</groupId> <artifactId>SSHWeb</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <!-- 声明变量,下面用类似于el表达式提取 --> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>4.2.4.RELEASE</spring.version> <mysql.version>5.1.37</mysql.version> <aspectj.version>1.6.10</aspectj.version> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> <!-- spring 依赖包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <!-- myql 依赖包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.0.7.Final</version> </dependency> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-convention-plugin</artifactId> <version>2.3.24</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>2.3.24</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-json-plugin</artifactId> <version>2.3.24</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-spring-plugin</artifactId> <version>2.3.24</version> </dependency> <!-- slf4j 依赖包 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.5</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.0-rc1</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.0-rc1</version> </dependency> </dependencies> <build> <!-- 配置了很多插件 --> <plugins> <!-- 编译插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.7</source> <target>1.7</target> <encoding>UTF-8</encoding> </configuration> </plugin> <!-- tomcat7插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>80</port> <path>/ssh</path> <uriEncoding>UTF-8</uriEncoding> <server>tomcat7</server> </configuration> </plugin> </plugins> </build> </project>
2.配置文件介绍:
1.db.properties和log4j.properties
hibernate.dialect=org.hibernate.dialect.MySQLDialect driverClassName=com.mysql.jdbc.Driver validationQuery=SELECT 1 url=jdbc:mysql://localhost:3306/hibernate?useUnicode=true&characterEncoding=UTF-8 username=sa password=123456 hibernate.hbm2ddl.auto=update hibernate.show_sql=true hibernate.format_sql=true
log4j.rootLogger=debug,A,B log4j.appender.A=org.apache.log4j.ConsoleAppender log4j.appender.A.layout=org.apache.log4j.PatternLayout log4j.appender.A.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n log4j.appender.B=org.apache.log4j.RollingFileAppender log4j.appender.B.Threshold=info log4j.appender.B.File=E:\\ssh.log log4j.appender.B.MaxFileSize=10MB log4j.appender.B.MaxBackupIndex=5 log4j.appender.B.layout=org.apache.log4j.PatternLayout log4j.appender.B.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n
1.spring相关配置文件:
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" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd "> <!-- 引入属性文件 --> <context:property-placeholder location="classpath:db.properties" /> <!-- 自动扫描dao和service包(自动注入) --> <context:component-scan base-package="cn.qlq" /> </beans>
spring-hibernate.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: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-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd "> <!-- 使用C3P0数据源,MySQL数据库 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <!-- MySQL5 --> <property name="driverClass" value="${driverClassName}"></property> <property name="jdbcUrl" value="${url}"></property> <property name="user" value="${username}"></property> <property name="password" value="${password}"></property> <property name="maxPoolSize" value="40"></property> <property name="minPoolSize" value="1"></property> <property name="initialPoolSize" value="1"></property> <property name="maxIdleTime" value="20"></property> </bean> <!-- session工厂 --> <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocations" value="classpath:hibernate.cfg.xml"></property> <property name="packagesToScan" value="cn.qlq.domain" /> <property name="hibernateProperties"> <props> <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> <prop key="hibernate.format_sql">${hibernate.format_sql}</prop> </props> </property> </bean> <!-- 配置事务 --> <bean name="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <tx:annotation-driven transaction-manager="txManager" /> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate5.HibernateTemplate"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> </beans>
2.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> <constant name="struts.i18n.encoding" value="utf-8"></constant> <constant name="devMode" value="true"></constant> <constant name="struts.enable.DynamicMethodInvocation" value="true" /> <constant name="" value="true" /> <!-- 配置拦截的后缀 --> <constant name="struts.action.extension" value="action,do" /> <!-- 与spring整合 --> <constant name="struts.objectFactory" value="spring"></constant> <package name="default" extends="json-default"></package> </struts>
3.hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <mapping resource="cn/qlq/domain/Customer.hbm.xml" /> <mapping resource="cn/qlq/domain/LinkMan.hbm.xml" /> </session-factory> </hibernate-configuration>
4.web.xml
spring监听器、配置文件路径、hibernate会话过滤器(一次请求前开启session,请求完成关闭session)、struts入口过滤器(注意hibernate打开会话过滤器必须配置在struts入口前面)
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <display-name>ssh</display-name> <!-- Spring ApplicationContext配置文件的路径,可使用通配符,多个路径用,号分隔 此参数用于后面的Spring Context Loader --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring.xml,classpath:spring-hibernate.xml</param-value> </context-param> <!-- spring 监听器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Filter 定义 --> <!-- Character Encoding filter --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!--Hibernate的session丢失解决方法 --> <filter> <filter-name>openSessionInView</filter-name> <filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>openSessionInView</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- struts2 filter --> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
3.接下来就是测试代码:
0.实体类以及xml配置文件
Customer.java
package cn.qlq.domain; import java.util.HashSet; import java.util.Set; public class Customer { private Long cust_id; private String cust_name; private String cust_source; private String cust_industry; private String cust_level; private String cust_linkman; private String cust_phone; private String cust_mobile; //使用set集合,表达一对多关系 private Set<LinkMan> linkMens = new HashSet<LinkMan>(); public Set<LinkMan> getLinkMens() { return linkMens; } public void setLinkMens(Set<LinkMan> linkMens) { this.linkMens = linkMens; } public Long getCust_id() { return cust_id; } public void setCust_id(Long cust_id) { this.cust_id = cust_id; } public String getCust_name() { return cust_name; } public void setCust_name(String cust_name) { this.cust_name = cust_name; } public String getCust_source() { return cust_source; } public void setCust_source(String cust_source) { this.cust_source = cust_source; } public String getCust_industry() { return cust_industry; } public void setCust_industry(String cust_industry) { this.cust_industry = cust_industry; } public String getCust_level() { return cust_level; } public void setCust_level(String cust_level) { this.cust_level = cust_level; } public String getCust_linkman() { return cust_linkman; } public void setCust_linkman(String cust_linkman) { this.cust_linkman = cust_linkman; } public String getCust_phone() { return cust_phone; } public void setCust_phone(String cust_phone) { this.cust_phone = cust_phone; } public String getCust_mobile() { return cust_mobile; } public void setCust_mobile(String cust_mobile) { this.cust_mobile = cust_mobile; } @Override public String toString() { return "Customer [cust_id=" + cust_id + ", cust_name=" + cust_name + "]"; } public Customer(Long cust_id, String cust_name) { super(); this.cust_id = cust_id; this.cust_name = cust_name; } public Customer() { } }
Customer.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 package="cn.qlq.domain" > <class name="Customer" table="cst_customer"> <id name="cust_id" > <generator class="native"></generator> </id> <property name="cust_name" column="cust_name" > </property> <property name="cust_source" column="cust_source" ></property> <property name="cust_industry" column="cust_industry" ></property> <property name="cust_level" column="cust_level" ></property> <property name="cust_linkman" column="cust_linkman" ></property> <property name="cust_phone" column="cust_phone" ></property> <property name="cust_mobile" column="cust_mobile" ></property> <!-- lazy属性: 决定是否延迟加载 true(默认值): 延迟加载,懒加载 false: 立即加载 extra: 极其懒惰 fetch属性: 决定加载策略.使用什么类型的sql语句加载集合数据 select(默认值): 单表查询加载 join: 使用多表查询加载集合 subselect:使用子查询加载集合 --> <!-- batch-size: 5 抓取集合的数量为5. 抓取客户的集合时,一次抓取几个客户的联系人集合. --> <set name="linkMens" batch-size="5"> <key column="lkm_cust_id" ></key> <one-to-many class="LinkMan" /> </set> </class> </hibernate-mapping>
LinkMan.java
package cn.qlq.domain; //联系人实体 public class LinkMan { private Long lkm_id; private Character lkm_gender; private String lkm_name; private String lkm_phone; private String lkm_email; private String lkm_qq; private String lkm_mobile; private String lkm_memo; private String lkm_position; // 表达多对一关系 private Customer customer; public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } public Long getLkm_id() { return lkm_id; } public void setLkm_id(Long lkm_id) { this.lkm_id = lkm_id; } public Character getLkm_gender() { return lkm_gender; } public void setLkm_gender(Character lkm_gender) { this.lkm_gender = lkm_gender; } public String getLkm_name() { return lkm_name; } public void setLkm_name(String lkm_name) { this.lkm_name = lkm_name; } public String getLkm_phone() { return lkm_phone; } public void setLkm_phone(String lkm_phone) { this.lkm_phone = lkm_phone; } public String getLkm_email() { return lkm_email; } public void setLkm_email(String lkm_email) { this.lkm_email = lkm_email; } public String getLkm_qq() { return lkm_qq; } public void setLkm_qq(String lkm_qq) { this.lkm_qq = lkm_qq; } public String getLkm_mobile() { return lkm_mobile; } public void setLkm_mobile(String lkm_mobile) { this.lkm_mobile = lkm_mobile; } public String getLkm_memo() { return lkm_memo; } public void setLkm_memo(String lkm_memo) { this.lkm_memo = lkm_memo; } public String getLkm_position() { return lkm_position; } public void setLkm_position(String lkm_position) { this.lkm_position = lkm_position; } @Override public String toString() { return "LinkMan [lkm_id=" + lkm_id + ", lkm_gender=" + lkm_gender + ", lkm_name=" + lkm_name + ", lkm_phone=" + lkm_phone + ", lkm_email=" + lkm_email + ", lkm_qq=" + lkm_qq + ", lkm_mobile=" + lkm_mobile + ", lkm_memo=" + lkm_memo + ", lkm_position=" + lkm_position + ", customer=" + customer + "]"; } }
LinkMan.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 package="cn.qlq.domain" > <class name="LinkMan" table="cst_linkman" > <id name="lkm_id" > <generator class="native"></generator> </id> <property name="lkm_gender" ></property> <property name="lkm_name" ></property> <property name="lkm_phone" ></property> <property name="lkm_email" ></property> <property name="lkm_qq" ></property> <property name="lkm_mobile" ></property> <property name="lkm_memo" ></property> <property name="lkm_position" ></property> <!-- fetch 决定加载的sql语句 select: 使用单表查询 join : 多表查询 (会导致lazy失效) lazy 决定加载时机 false: 立即加载 proxy: 由customer的类级别加载策略决定. --> <many-to-one name="customer" column="lkm_cust_id" class="Customer" fetch="join" lazy="proxy"></many-to-one> </class> </hibernate-mapping>
1.dao接口以及实现
package cn.qlq.dao; import org.hibernate.Session; import cn.qlq.domain.Customer; public interface CustomerDao { /** * 保存客户 * * @param c */ public void saveCustomer(Customer c); /** * 根据ID查询 * * @param cusId * @return */ public Customer getCustomerById(Long cusId); /** * 测试通过hibernate获取的session是否同一线程是一样的 */ public Session testSessionIsSameInOneThread(); }
package cn.qlq.dao; import java.io.Serializable; import java.util.List; import javax.annotation.Resource; import org.hibernate.Criteria; import org.hibernate.Query; import org.hibernate.SQLQuery; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.criterion.Restrictions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.orm.hibernate5.support.HibernateDaoSupport; import org.springframework.stereotype.Repository; import cn.qlq.domain.Customer; /** * dao操作一般继承HibernateDaoSupport,里面获取hibernateTemplete也可以进行许多操作 * * @author liqiang * */ @Repository public class CustomerDaoImpl extends HibernateDaoSupport implements CustomerDao { private static Logger log = LoggerFactory.getLogger(CustomerDaoImpl.class); @Override public void saveCustomer(Customer c) { Serializable obj = getHibernateTemplate().save(c);// 返回值是生成的主键的值 log.info("save customer success,userId is:{}", obj.toString()); } @Resource public void setSessionFacotry(SessionFactory sessionFacotry) { super.setSessionFactory(sessionFacotry); } @Override public Customer getCustomerById(Long cusId) { // 第一种:session.get方法 Session session = getSessionFactory().openSession(); Customer customer = session.get(Customer.class, cusId); log.info("第一种方法(session获取):{}", customer.toString()); // 第二种:HQL String hql = "from Customer where cust_id=" + cusId; Query query = session.createQuery(hql); Customer cus = (Customer) query.uniqueResult(); log.info("第二种方法(HQL获取):{}", customer.toString()); // 第三种:Criteria查询 Criteria c = session.createCriteria(Customer.class); c.add(Restrictions.eq("cust_name", "ttt")); List list = c.list(); log.info("Criteria方法获取的:{}", list.toString()); // 第四种:原生SQL查询 String sql = "select * from cst_customer where cust_id = " + cusId; SQLQuery sqlQuery = session.createSQLQuery(sql); sqlQuery.addEntity(Customer.class); log.info("原生SQL查询方法获取的:{}", sqlQuery.list().toString()); return customer; } @Override public Session testSessionIsSameInOneThread() { return getHibernateTemplate().getSessionFactory().getCurrentSession(); } }
dao实现一般要继承HibernateDaoSupport,我们项目中也是采用所有的Dao都继承HibernateDaoSupport。这个抽象类有好多直接可以用的方法。原理都是调用hibernateTemplate。所以在Dao实现层我们可以选择继承HibernateDaoSupport,或者直接注入HibernateTemplate。
也可以用HibernateTemplate进行操作(直接注入HibernateTemplate),此方法的实例我们已经在XML中注入,通过此对象可以获取session执行原生SQL,或者直接注入SessionFactory获取Session(不建议这种)。
2.service接口和实现
package cn.qlq.service; import cn.qlq.domain.Customer; public interface CustomerService { public boolean saveCustomer(Customer c); /** * 根据ID查询 * * @param cusId * @return */ public Customer getCustomerById(Long cusId); /** * 测试通过hibernateTemplete获取的session是否同一线程是一样的 */ public boolean testSessionIsSameInOneThread(); }
package cn.qlq.service; import org.hibernate.Session; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.orm.hibernate5.HibernateTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import cn.qlq.dao.CustomerDao; import cn.qlq.domain.Customer; @Service @Transactional public class CustomerServiceImpl implements CustomerService { private static Logger log = LoggerFactory.getLogger(CustomerServiceImpl.class); @Autowired private CustomerDao customerDao; @Autowired private HibernateTemplate hibernateTemplate; @Override public boolean saveCustomer(Customer c) { customerDao.saveCustomer(c); return true; } @Override public Customer getCustomerById(Long cusId) { return customerDao.getCustomerById(cusId); } @Override public boolean testSessionIsSameInOneThread() { //getCurrentSession获取与线程绑定的session(返回true),而openSession不是同一个(会返回false) // Session serviceSession = hibernateTemplate.getSessionFactory().openSession(); Session serviceSession = hibernateTemplate.getSessionFactory().getCurrentSession(); log.info("serviceSession---------------{}", serviceSession.toString()); Session daoSession = customerDao.testSessionIsSameInOneThread(); log.info("daoSession---------------{}", daoSession.toString()); log.info("daoSession.equals(serviceSession) is :{}", daoSession.equals(serviceSession)); return daoSession.equals(serviceSession); } }
3.Action层代码
package cn.qlq.action; import java.util.HashMap; import java.util.Map; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Namespace; import org.apache.struts2.convention.annotation.ParentPackage; import org.apache.struts2.convention.annotation.Result; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import cn.qlq.domain.Customer; import cn.qlq.service.CustomerService; /** * 客户Action * * @author liqiang * */ @Namespace("/cus") @ParentPackage("default") @SuppressWarnings("all") public class CustomerAction { private static Logger log = LoggerFactory.getLogger(CustomerAction.class); @Autowired private CustomerService customerService; private Map responseMap = new HashMap(); private Customer c;// 对象驱动保存对象 @Action(value = "saveCus", results = { @Result(name = "success", type = "json", params = { "root", "responseMap" }) }) public String saveCus() { try { customerService.saveCustomer(c); } catch (Exception e) { responseMap.put("msg", "保存客户失败!"); return "success"; } responseMap.put("msg", "保存客户成功!"); return "success"; } @Action(value = "getCusById", results = { @Result(name = "success", type = "json", params = { "root", "responseMap" }) }) public String getCusById() { Customer cus = null; try { cus = customerService.getCustomerById(15l); } catch (Exception e) { responseMap.put("msg", "查询客户失败!"); return "success"; } responseMap.put("msg", "查询客户成功!"); responseMap.put("data", cus); return "success"; } @Action(value = "testSessionIsSameInOneThread", results = { @Result(name = "success", type = "json", params = { "root", "responseMap" }) }) public String testSessionIsSameInOneThread() { responseMap.put("data", customerService.testSessionIsSameInOneThread()); return "success"; } public Customer getC() { return c; } public void setC(Customer c) { this.c = c; } public Map getResponseMap() { return responseMap; } public void setResponseMap(Map responseMap) { this.responseMap = responseMap; } }
3.测试(就不搭建页面了,直接get请求访问根据返回的JSON值判断结果)
1.测试保存:
http://localhost/SSHWeb/cus/saveCus.do?c.cust_name=ttt
结果:
日志:
2018-08-25 20:42:19 [cn.qlq.dao.CustomerDaoImpl]-[INFO] save customer success,userId is:18
2.测试查询:
http://localhost/SSHWeb/cus/getCusById.do
结果:(会关联查询联系人)
日志:
2018-08-25 20:45:26 [cn.qlq.dao.CustomerDaoImpl]-[INFO] 第一种方法(session获取):Customer [cust_id=15, cust_name=ttt]
2018-08-25 20:45:27 [cn.qlq.dao.CustomerDaoImpl]-[INFO] 第二种方法(HQL获取):Customer [cust_id=15, cust_name=ttt]
2018-08-25 20:45:27 [cn.qlq.dao.CustomerDaoImpl]-[INFO] Criteria方法获取的:[Customer [cust_id=15, cust_name=ttt], Customer [cust_id=18, cust_name=ttt]]
2018-08-25 20:45:27 [cn.qlq.dao.CustomerDaoImpl]-[INFO] 原生SQL查询方法获取的:[Customer [cust_id=15, cust_name=ttt]]
3.测试获取与线程绑定的Session
http://localhost/SSHWeb/cus/testSessionIsSameInOneThread.do
结果:
日志:
2018-08-25 20:47:16 [cn.qlq.service.CustomerServiceImpl]-[INFO] serviceSession---------------SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null]) 2018-08-25 20:47:16 [cn.qlq.service.CustomerServiceImpl]-[INFO] daoSession---------------SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null]) 2018-08-25 20:47:16 [cn.qlq.service.CustomerServiceImpl]-[INFO] daoSession.equals(serviceSession) is :true
4.测试事务(一般我们都要在service层打事务注解进行事务控制)
上面的搭建环境基本完成了,但是事务控制非常重要,下面测试事务是否生效。
原来数据:
mysql> select * from cst_customer; +---------+-----------+-------------+---------------+------------+------------- | cust_id | cust_name | cust_source | cust_industry | cust_level | cust_linkman +---------+-----------+-------------+---------------+------------+------------- | 15 | ttt | NULL | NULL | NULL | NULL | 18 | ttt | NULL | NULL | NULL | NULL +---------+-----------+-------------+---------------+------------+------------- 2 rows in set (0.00 sec)
1.测试事务是否生效
service层制造一个保存之后的异常,修改保存的代码:
访问请求:
http://localhost/SSHWeb/cus/saveCus.do?c.cust_name=ttt
结果:
日志
Hibernate: insert into cst_customer (cust_name, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_mobile) values (?, ?, ?, ?, ?, ?, ?) 2018-08-25 20:54:19 [cn.qlq.dao.CustomerDaoImpl]-[INFO] save customer success,userId is:19 2018-08-25 20:54:19 [org.springframework.orm.hibernate5.HibernateTransactionManager]-[DEBUG] Initiating transaction rollback 2018-08-25 20:54:19 [org.springframework.orm.hibernate5.HibernateTransactionManager]-[DEBUG] Rolling back Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[EntityKey[cn.qlq.domain.Customer#19]],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] 2018-08-25 20:54:19 [org.springframework.orm.hibernate5.HibernateTransactionManager]-[DEBUG] Not closing pre-bound Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] after transaction 2018-08-25 20:54:19 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] trace [email protected] [managed: 5, unused: 3, excluded: 0] (e.g. [email protected]) 2018-08-25 20:54:19 [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] Returning cached instance of singleton bean ‘org.springframework.transaction.config.internalTransactionAdvisor‘ 2018-08-25 20:54:19 [org.apache.struts2.json.JSONUtil]-[DEBUG] [JSON]{"msg":"保存客户失败!"}
分析:
插进去数据之后报异常然后进行 回滚操作,证明事务生效。
为了验证,我们在查询数据库:
mysql> select * from cst_customer; +---------+-----------+-------------+---------------+------------+------------ | cust_id | cust_name | cust_source | cust_industry | cust_level | cust_linkma +---------+-----------+-------------+---------------+------------+------------ | 15 | ttt | NULL | NULL | NULL | NULL | 18 | ttt | NULL | NULL | NULL | NULL +---------+-----------+-------------+---------------+------------+------------ 2 rows in set (0.00 sec)
2.在还存在异常的情况下,我们将事务注解去掉:
补充:
进行此测试,我们首先需要将重写OpenSessionInViewFilter过滤器的openSession方法,否则报错:Write operations are not allowed in read-only mode (FlushMode.MANUAL),
参考:https://www.cnblogs.com/qlqwjy/p/9535500.html
访问请求:
http://localhost/SSHWeb/cus/saveCus.do?c.cust_name=ttt
结果:
日志: (虽然报错了,但是错误是在执行save之后,所以会提交数据库并且没有事务控制不会回滚,造成异常数据)
Hibernate: insert into cst_customer (cust_name, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_mobile) values (?, ?, ?, ?, ?, ?, ?) 2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] acquire test -- pool size: 1; target_pool_size: 1; desired target? 2 2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] incremented pending_acquires: 1 2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] incremented pending_acquires: 2 2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] incremented pending_acquires: 3 2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] awaitAvailable(): [email protected] 2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] trace [email protected] [managed: 1, unused: 0, excluded: 0] (e.g. [email protected]) 2018-08-25 21:38:52 [com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool]-[DEBUG] com.mchange.v2.c3p0.imp[email protected]204746c3.acquireResource() returning. 2018-08-25 21:38:52 [com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool]-[DEBUG] com.mchange.v2.c3p0.imp[email protected]204746c3.acquireResource() returning. 2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] trace [email protected] [managed: 2, unused: 1, excluded: 0] (e.g. [email protected]) 2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] decremented pending_acquires: 2 2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] trace [email protected] [managed: 3, unused: 2, excluded: 0] (e.g. [email protected]) 2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] decremented pending_acquires: 1 2018-08-25 21:38:52 [com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool]-[DEBUG] com.mchange.v2.c3p0.imp[email protected]204746c3.acquireResource() returning. 2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] trace [email protected] [managed: 4, unused: 3, excluded: 0] (e.g. [email protected]) 2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] decremented pending_acquires: 0 2018-08-25 21:38:52 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] trace [email protected] [managed: 4, unused: 2, excluded: 0] (e.g. [email protected]) 2018-08-25 21:38:52 [cn.qlq.dao.CustomerDaoImpl]-[INFO] save customer success,userId is:20 2018-08-25 21:38:55 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] Checking for expired resources - Sat Aug 25 21:38:55 CST 2018 [[email protected]] 2018-08-25 21:38:55 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] BEGIN check for expired resources. [[email protected]] 2018-08-25 21:38:55 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] FINISHED check for expired resources. [[email protected]] 2018-08-25 21:39:00 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] Checking for expired resources - Sat Aug 25 21:39:00 CST 2018 [[email protected]] 2018-08-25 21:39:00 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] BEGIN check for expired resources. [[email protected]] 2018-08-25 21:39:00 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] FINISHED check for expired resources. [[email protected]] 2018-08-25 21:39:05 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] Checking for expired resources - Sat Aug 25 21:39:05 CST 2018 [[email protected]] 2018-08-25 21:39:05 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] BEGIN check for expired resources. [[email protected]] 2018-08-25 21:39:05 [com.mchange.v2.resourcepool.BasicResourcePool]-[DEBUG] FINISHED check for expired resources. [[email protected]] 2018-08-25 21:39:07 [cn.qlq.action.CustomerAction]-[ERROR] java.lang.ArithmeticException: / by zero at cn.qlq.service.CustomerServiceImpl.saveCustomer(CustomerServiceImpl.java:27) at cn.qlq.action.CustomerAction.saveCus(CustomerAction.java:40) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
查看SQL:
mysql> select * from cst_customer; +---------+-----------+-------------+---------------+------------+------------- | cust_id | cust_name | cust_source | cust_industry | cust_level | cust_linkman +---------+-----------+-------------+---------------+------------+------------- | 15 | ttt | NULL | NULL | NULL | NULL | 18 | ttt | NULL | NULL | NULL | NULL | 20 | ttt | NULL | NULL | NULL | NULL +---------+-----------+-------------+---------------+------------+------------- 3 rows in set (0.00 sec)
总结:
证明我们上面的事务配置 是正确,并且也生效了。总结出来一条:在我们进行增(save)、改(update)、删(delete)的时候要在service层打上注解,否则会报Write operations are not allowed in read-only mode (FlushMode.MANUAL),除非我们重写OpenSessionInViewFilter的openSession方法(一般不推荐这种)。
5.测试DAO直接注入hibernateTemplate:
1.dao代码
package cn.qlq.dao; import org.hibernate.Session; import cn.qlq.domain.Customer; public interface CustomerDao2 { /** * 保存客户 * * @param c */ public void saveCustomer(Customer c); /** * 根据ID查询 * * @param cusId * @return */ public Customer getCustomerById(Long cusId); /** * 测试通过hibernate获取的session是否同一线程是一样的 */ public Session testSessionIsSameInOneThread(); }
package cn.qlq.dao; import java.io.Serializable; import java.util.List; import javax.annotation.Resource; import org.hibernate.Criteria; import org.hibernate.FlushMode; import org.hibernate.Query; import org.hibernate.SQLQuery; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.criterion.Restrictions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.orm.hibernate5.HibernateTemplate; import org.springframework.orm.hibernate5.support.HibernateDaoSupport; import org.springframework.stereotype.Repository; import cn.qlq.domain.Customer; /** * * 测试Dao层直接注入hibernateTemplate * * @author liqiang * */ @Repository public class CustomerDaoImpl2 implements CustomerDao2 { private static Logger log = LoggerFactory.getLogger(CustomerDaoImpl2.class); @Autowired private HibernateTemplate hibernateTemplate; @Override public void saveCustomer(Customer c) { Serializable obj = hibernateTemplate.save(c);// 返回值是生成的主键的值 log.info("save customer success,userId is:{}", obj.toString()); } @Override public Customer getCustomerById(Long cusId) { // 第一种:session.get方法 Session session = hibernateTemplate.getSessionFactory().openSession(); Customer customer = session.get(Customer.class, cusId); log.info("第一种方法(session获取):{}", customer.toString()); // 第二种:HQL String hql = "from Customer where cust_id=" + cusId; Query query = session.createQuery(hql); Customer cus = (Customer) query.uniqueResult(); log.info("第二种方法(HQL获取):{}", customer.toString()); // 第三种:Criteria查询 Criteria c = session.createCriteria(Customer.class); c.add(Restrictions.eq("cust_name", "ttt")); List list = c.list(); log.info("Criteria方法获取的:{}", list.toString()); // 第四种:原生SQL查询 String sql = "select * from cst_customer where cust_id = " + cusId; SQLQuery sqlQuery = session.createSQLQuery(sql); sqlQuery.addEntity(Customer.class); log.info("原生SQL查询方法获取的:{}", sqlQuery.list().toString()); return customer; } @Override public Session testSessionIsSameInOneThread() { return hibernateTemplate.getSessionFactory().getCurrentSession(); } }
2.service代码:
3.Action层代码:
/** * 测试Dao层直接注入hibernateTemplate * * @return */ @Action(value = "saveCus2", results = { @Result(name = "success", type = "json", params = { "root", "responseMap" }) }) public String saveCus2() { try { customerService.saveCustomer2(c); } catch (Exception e) { log.error("", e); responseMap.put("msg", "保存客户失败!"); return "success"; } responseMap.put("msg", "保存客户成功!"); return "success"; }
4.测试:
http://localhost/SSHWeb/cus/saveCus2.do?c.cust_name=ttt2
结果:
6.总结:
SSH整合与SSM整合大体类似,在这里就基本完成了SSH的整合。总结一下SSH整合过程。
1.Struts配置:配置struts的对象工程为spring,然后struts采用注解配置,struts整合spring比较简单
2.spring:配置扫描的包,引入配置文件。
3.spring整合hibernate:配置数据源(连接池)、
配置sessionFactory(注入数据源、hibernate配置文件位置(configLocations)、hibernate一些打印SQL等配置(hibernateProperties))
配置事务管理器并开启注解事务。
配置hibernateTemplate,需要注入会话工厂(sessionFactory)
接下来还有hibernate的二级缓存与注解的使用未完成,将会在之后补充。
原文地址:https://www.cnblogs.com/qlqwjy/p/9535626.html