上一篇:Spring学习之在eclipse中使用maven创建springMVC项目
下一篇:Spring学习之整合Activiti(一)
本文是在Spring学习之在eclipse中使用maven创建springMVC项目的基础上完成的,所以不清楚的可以点击查看。
一、创建数据库与表
启动MySQL,创建数据库,新建表user,完成后的表如下所示:
sql语句为:
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` varchar(255) NOT NULL COMMENT '用户id',
`code` varchar(255) DEFAULT NULL COMMENT '用户code',
`name` varchar(255) DEFAULT NULL COMMENT '用户名',
`password` varchar(255) DEFAULT NULL COMMENT '用户密码',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户数据表';
二、添加依赖包:
在pom.xml中添加对MyBatis的依赖,主要有:Spring jdbc包、MyBatis ORM包、MyBatis-Spring适配包、Log4j2等,具体新增的依赖如下:
<!-- myBatis start -->
<!--Spring java数据库访问包,在本例中主要用于提供数据源 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--mysql数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<!-- mybatis ORM框架 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
<!--mybatis-spring适配器 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<!--log4j日志包 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.6.1</version>
</dependency>
<!-- myBatis end -->
保存后,新增如下包:
三、新建POJO实体层:
为了实现与数据库中的user表进行关系映射新建一个User类,具体代码如下:
package com.zr.activiti.entity;
/**
* 用户实体
* @author Administrator
*
*/
public class User {
private String userId;
private String userCode;
private String userName;
private String password;
public User(String userId, String userCode, String userName, String password) {
super();
this.userId = userId;
this.userCode = userCode;
this.userName = userName;
this.password = password;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserCode() {
return userCode;
}
public void setUserCode(String userCode) {
this.userCode = userCode;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
四、新建MyBatis SQL映射层:
这个项目中我们采用接口与xml结构的形式完成关系与对象间的映射,在接口中定义一些数据访问的方法,在xml文件中定义实现数据访问需要的sql脚本。
4.1 用户数据访问映射接口如下
package com.zr.activiti.dao;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.zr.activiti.entity.User;
/**
* 用户数据访问接口
* @author Administrator
*
*/
public interface UserDAO {
public List<User> getAllUsers();
public User getUserById(@Param("id")String id);
public User getUserByUserCode(@Param("code")String userCode);
public int add(User user);
public int delete(@Param("id")String id);
public int update(User user);
}
4.2 创建MyBatis ORM的映射文件UserMapper.xml(命名尽量都遵循一个规则,便于扫描,这里约定以实体名+Mapper)。
本项目为方便管理,在resources目录下新建mybatis/mappers目录,在该目录下新建UserMapper.xml
如图所示:
UserMapper.xml 内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--命名空间应该是对应接口的包名+接口名 -->
<mapper namespace="com.zr.activiti.dao.UserDAO">
<resultMap type="com.zr.activiti.entity.User" id="requireResult">
<result property="userId" column="id"/>
<result property="userCode" column="code"/>
<result property="userName" column="name"/>
<result property="password" column="password"/>
</resultMap>
<!--id应该是接口中的方法,结果类型如没有配置别名则应该使用全名称 -->
<select id="getAllUsers" resultMap="requireResult">
SELECT * FROM user
</select>
<!-- 模糊查询用户 -->
<select id="findLike" parameterType="User" resultMap="UserSomeResult">
SELECT * FROM user where 1=1
<if test="userCode != null" >
and code like CONCAT("%","${userCode}","%")
</if>
<if test="userName != null" >
and name like CONCAT("%","${userName}","%")
</if>
<if test="password != null" >
and password=#{password}
</if>
order by name desc
</select>
<select id="getUserById" resultMap="requireResult">
SELECT * FROM user WHERE id = #{userId}
</select>
<select id="getUserByCode" resultMap="requireResult">
SELECT * FROM user WHERE id = #{userCode}
</select>
<insert id="add">
INSERT INTO user (id,code,name,password)
VALUES (#{userId},#{userCode},#{userName},#{password})
</insert>
<delete id="delete">
DELETE FROM user WHERE id=#{userId}
</delete>
<delete id="deleteAll">
DELETE FROM user
</delete>
<update id="update">
UPDATE user
<set >
<if test="userCode != null" >
code =#{userCode},
</if>
<if test="userName != null" >
name=#{userName},
</if>
<if test="password != null" >
password=#{password},
</if>
</set>
where id=#{userId}
</update>
</mapper>
五、完成Spring整合MyBatis配置:
5.1 在resources根目录下新建 jdbc.properties文件,用于存放数据库连接信息,目录如下:
jdbc.properties文件内容如下:
#mysql jdbc
jdbc.driver=com.mysql.jdbc.Driver
#activitidb指的是本地数据库名
jdbc.url=jdbc:mysql://127.0.0.1:3306/activitidb?zeroDateTimeBehavior=round&useUnicode=yes&characterEncoding=UTF8
#mysql登录用户名
jdbc.username=root
#mysql登录密码
jdbc.password=(自己设置的密码)
在没有Spring的环境下我们单纯使用MyBatis ORM框架时,我们是通过MyBatisCfg.xml完成sqlSessionFactory的构建工作,如果使用Spring则这部分配置的内容可以完全由Spring容器替代,这部分可以在springContext.xml中添加,这里同样为方便管理,我们在spring目录新建一个spring-mybatis.xml,结构如下:
spring-mybatis.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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!--1 引入属性文件,在配置中占位使用 -->
<context:property-placeholder location="classpath*:jdbc.properties" />
<!--2 配置一个Spring提供的数据源 :jdbc数据源,创建一个驱动管理数据源的bean -->
<bean id="jdbcDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!--3 会话工厂bean sqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 数据源 -->
<property name="dataSource" ref="jdbcDataSource"></property>
<!-- 别名 -->
<property name="typeAliasesPackage" value="com.zr.activiti.entity"></property>
<!-- sql映射文件路径 -->
<!-- 扫描mappers目录以及子目录下的所有xml文件 -->
<property name="mapperLocations" value="classpath:mybatis/mappers/**/*.xml" />
</bean>
<!--4 自动扫描对象关系映射 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--指定会话工厂,如果当前上下文中只定义了一个则该属性可省去 -->
<!-- <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> -->
<!-- basePackage 属性是让你为映射器接口文件设置基本的包路径。 你可以使用分号或逗号 作为分隔符设置多于一个的包路径 -->
<property name="basePackage" value="com.zr.workflow.activiti.dao,com.zr.workflow.springdemo.dao" />
</bean>
<!--5 声明式事务管理 -->
<!--定义事物管理器,由spring管理事务 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="jdbcDataSource"></property>
</bean>
<!--支持注解驱动的事务管理,指定事务管理器 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
我们当前的示例使用的是Spring提供的数据源,其实也可以使用一第三方的数据源管理,如C3P0,Druid(德鲁伊,阿里巴巴开发)等。
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。C3P0数据源在项目开发中使用得比较多。dbcp没有自动回收空闲连接的功能,而c3p0有自动回收空闲连接功能。
在pom.xml中添加依赖:
<!--c3p0 连接池 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
在与Spring整合时修改spring-mybatis.xml,设置如下:
<!--定义一个jdbc数据源,创建一个驱动管理数据源的bean -->
<bean id="jdbcDataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.uid}" />
<property name="password" value="${jdbc.pwd}" />
<property name="acquireIncrement" value="5"></property>
<property name="initialPoolSize" value="10"></property>
<property name="minPoolSize" value="5"></property>
<property name="maxPoolSize" value="20"></property>
</bean>
Druid首先是一个数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个SQL Parser。阿里巴巴是一个重度使用关系数据库的公司,我们在生产环境中大量的使用Druid,通过长期在极高负载的生产环境中实际使用、修改和完善,让Druid逐步发展成最好的数据库连接池。Druid在监控、可扩展性、稳定性和性能方面都有明显的优势。
在pom.xml中添加依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.20</version>
</dependency>
在与Spring整合时修改spring-mybatis.xml,设置:
<!-- 配置数据源,使用的是alibaba的Druid(德鲁伊)数据源 -->
<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${jdbc_url}" />
<property name="username" value="${jdbc_username}" />
<property name="password" value="${jdbc_password}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="0" />
<!-- 连接池最大使用连接数量 -->
<property name="maxActive" value="20" />
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="20" />
<!-- 连接池最小空闲 -->
<property name="minIdle" value="0" />
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="60000" />
<!--
<property name="poolPreparedStatements" value="true" />
<property name="maxPoolPreparedStatementPerConnectionSize" value="33" />
-->
<property name="validationQuery" value="${validationQuery}" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="testWhileIdle" value="true" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="25200000" />
<!-- 打开removeAbandoned功能 -->
<property name="removeAbandoned" value="true" />
<!-- 1800秒,也就是30分钟 -->
<property name="removeAbandonedTimeout" value="1800" />
<!-- 关闭abanded连接时输出错误日志 -->
<property name="logAbandoned" value="true" />
<!-- 监控数据库 -->
<!-- <property name="filters" value="stat" /> -->
<property name="filters" value="mergeStat" />
</bean>
mapperLocations:它表示我们的Mapper文件存放的位置,当我们的Mapper文件跟对应的Mapper接口处于同一位置的时候可以不用指定该属性的值。
configLocation:用于指定Mybatis的配置文件位置。如果指定了该属性,那么会以该配置文件的内容作为配置信息构建对应的SqlSessionFactoryBuilder,但是后续属性指定的内容会覆盖该配置文件里面指定的对应内容。
typeAliasesPackage:它一般对应我们的实体类所在的包,这个时候会自动取对应包中不包括包名的简单类名作为包括包名的别名。多个package之间可以用逗号或者分号等来进行分隔。
typeAliases:数组类型,用来指定别名的。指定了这个属性后,Mybatis会把这个类型的短名称作为这个类型的别名,前提是该类上没有标注@Alias注解,否则将使用该注解对应的值作为此种类型的别名。
<property name="typeAliases">
<array>
<value>com.tiantian.mybatis.model.Blog</value>
<value>com.tiantian.mybatis.model.Comment</value>
</array>
</property>
需要注意的是这里的sql会话工厂的指定可以使用sqlSessionFactoryBeanName属性指定,也可以使用sqlSessionFactory属性指定,但建议大家使用sqlSessionFactoryBeanName,否则会因为加载的先后顺序问题引起读不到properties文件的内容。其它属性的设置可以查看源码后再定义。
这样MapperScannerConfigurer就会扫描指定basePackage下面的所有接口,并把它们注册为一个个MapperFactoryBean对象。basePackage下面的并不全是我们定义的Mapper接口,为此MapperScannerConfigurer还为我们提供了另外两个可以缩小搜索和注册范围的属性。一个是annotationClass,另一个是markerInterface。
annotationClass:当指定了annotationClass的时候,MapperScannerConfigurer将只注册使用了annotationClass注解标记的接口。
markerInterface:markerInterface是用于指定一个接口的,当指定了markerInterface之后,MapperScannerConfigurer将只注册继承自markerInterface的接口。
sqlSessionFactory: 已废弃 。当使用多个数据源时就需要通过sqlSessionFactory来指定注册MapperFactoryBean的时候需要使用的SqlSessionFactory,因为在没有指定sqlSessionFactory的时候,会以Autowired的方式自动注入一个。换言之当我们只使用一个数据源的时候,即只定义了一个SqlSessionFactory的时候我们就可以不给MapperScannerConfigurer指定SqlSessionFactory。
sqlSessionFactoryBeanName:它的功能跟sqlSessionFactory是一样的,只是它指定的是定义好的SqlSessionFactory对应的bean名称。
sqlSessionTemplate: 已废弃 。它的功能也是相当于sqlSessionFactory的,MapperFactoryBean最终还是使用的SqlSession的getMapper方法取的对应的Mapper对象。当定义有多个SqlSessionTemplate的时候才需要指定它。对于一个MapperFactoryBean来说SqlSessionFactory和SqlSessionTemplate只需要其中一个就可以了,当两者都指定了的时候,SqlSessionFactory会被忽略。
sqlSessionTemplateBeanName:指定需要使用的sqlSessionTemplate对应的bean名称。
六、JUnit测试类
为了确保服务类中的每个方法正确,先使用JUnit进行单元测试,测试代码如下:
package com.zr.activiti.test;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.zr.activiti.dao.UserDAO;
import com.zr.activiti.entity.User;
import com.zr.activiti.service.UserService;
import com.zr.activiti.utils.UUIDUtil;
public class TestUserService {
static UserService userService;
@Test
public void testUserDAO() {
//在当前上下文中获得Spring容器
ApplicationContext ctx=new ClassPathXmlApplicationContext("spring/spring-mybatis.xml");
UserDAO userDAO=ctx.getBean(UserDAO.class);
String userId = UUIDUtil.uuid();
System.out.println("TestUserService testUserDAO userId:"+userId);
User user1 =new User(userId, "zhangsan", "张三", "123456");
System.out.println("插入user:"+userDAO.add(user1));
//访问数据库
List<User> users=userDAO.getAllUsers();
for (User user : users) {
System.out.println("user:"+user);
}
assertNotNull(users);
}
@BeforeClass
public static void before() {
//在当前上下文中获得Spring容器,首先确认spring-mybatis.xml文件中已经有扫描UserService的配置,
//因为目前spring-mybatis.xml只配置了com.zr.activiti.dao包,如果要测试UserService中的方法,则加上:
//<context:component-scan base-package="com.zr.activiti"></context:component-scan>
ApplicationContext ctx=new ClassPathXmlApplicationContext("spring/spring-mybatis.xml");
userService=ctx.getBean(UserService.class);
}
@Test
public void testGetAllUsers() {
List<User> users = userService.getAllUsers();
assertNotNull(users);
}
@Test
public void testAdd() {
String userId = UUIDUtil.uuid();
System.out.println("TestUserService testAdd userId:"+userId);
User user=new User(userId, "zhangsan", "张三", "123456");
try {
assertEquals(1, userService.add(user));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testDelete() {
assertEquals(1, userService.delete("123"));
}
@Test
public void testDeleteStringArray() {
String[] ids={"123"};
assertEquals(3, userService.delete(ids));
}
@Test
public void testUpdate() {
String userId = UUIDUtil.uuid();
User user=new User(userId, "zhangsan", "张三", "123456");
try {
assertEquals(1, userService.update(user));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testGetBookById(){
assertNotNull(userService.getUserByCode("zhangsan"));
}
@Test
public void testAddDouble(){
//因为userId相同,添加第二个人会失败,用于测试事务
String userId = UUIDUtil.uuid();
User user=new User(userId, "wangwu", "王五", "123456");
// String userId2 = UUIDUtil.uuid();
User user2=new User(userId, "lisi", "李四", "123456");
assertEquals(2, userService.add(user, user2));
}
}
七、常见异常(持续收集中):
1、MYSQL:WARN: Establishing SSL connection without server's identity verification is not recommended.
在JDBC连接Mysql数据库的过程中出现了如下的警告信息:
WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
是Mysql数据库的SSL连接问题,提示警告不建议使用没有带服务器身份验证的SSL连接,是在MYSQL5.5.45+, 5.6.26+ and 5.7.6+版本中才有的这个问题。解决办法在警告中已经说明了:
1.在数据库连接的url中添加useSSL=false;
2.url中添加useSSL=true,并且提供服务器的验证证书。如果只是做一个测试的话,没必要搞证书那么麻烦啦,在连接后添加一个useSSL=false即可,例如
jdbc:mysql://127.0.0.1:3306/activitidb?useSSL=false&zeroDateTimeBehavior=round&useUnicode=yes&characterEncoding=UTF8
在使用Java进行JDBC连接的时候,可以在Properties对象中设置useSSL的值为false,但是和写在链接中是一样的。比如
Properties properties = new Properties();
properties.setProperty("user", "root");
properties.setProperty("password", "(自己设置的密码)");
properties.setProperty("useSSL", "false");
properties.setProperty("autoReconnect", "true");
try (Connection conn = DriverManager.getConnection(connectionUrl, properties)) {
...
} catch (SQLException e) {
...
}
上一篇:Spring学习之在eclipse中使用maven创建springMVC项目
下一篇:Spring学习之整合Activiti(一)