发表于: 2017-04-30 14:42:45
1 1325
Task1的第七天
情况说明
Spring+Mybatis整合的东西很多,脑袋有点乱,昨天日报没写出来,今天合在一起了。
旧工程往上添加东西已经有点费劲了,干脆新建了一个工程。Spring+Mybatis基本是整合完成了。
今日完成
配置Spring+MyBatis
Spring对Hibernate和JPA都进行了支持,但是没有对MyBatis进行支持。为什么呢?原因我们从MyBatis官网找到了解释。
正如第二版那样,Spring 3.0 也仅支持 iBatis2。那么,我们就想将 MyBatis3 的支持添加到 Spring3.0(参考 Spring Jira 中的问题)中。而不幸的是,Spring 3.0 的开发在 MyBatis 3.0 官方发布前就结束了。因为 Spring 开发团队不想发布一个基于非发布版的 MyBatis 的整合支持,那么 Spring 官方的支持就不得不继续等待了。要在 Spring 中支持 MyBatis,MyBatis 社区认为现在应该是自己团结贡献者和有兴趣的人一起来开始将 Spring 的整合作为 MyBatis 社区的子项目的时候了。
简单来说,就是MyBatis没有跟上Spring的发布脚步,Spring就撇下MyBatis了,然后MyBatis就自己做了一套整合包。
创建jdbc-properties
jdbc.properties
主要负责配置数据库驱动、数据库链接、数据库用户名和密码。
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/jnshu?useUnicode=true&characterEncoding=utf8&autoReconnect=true
jdbc.username=username
jdbc.password=password
创建mybatis-config.xml
mybatis-config.xml
不像之前的工程那样承担那么多事情,配置数据源和扫描映射文件都转移到了spring-dao.xml
中去做。
mybatis-config.xml
目前只负责对mybatis做一些设置
<!-- 配置全局属性 -->
<settings>
<!-- 使用jdbc的getGeneratedKeys获取数据库自增主键值 -->
<setting name="useGeneratedKeys" value="true" />
<!-- 使用列别名替换列名 默认:true -->
<setting name="useColumnLabel" value="true" />
<!-- 开启驼峰命名转换:Table{create_time} -> Entity{createTime} -->
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
创建Mapper接口
在原来工程的接口上做了一些修改。
创建mapper文件
也是在原来工程的文件上做了一些修改。
创建spring-dao.xml
spring-dao.xml
主要负责以下几件事情:
- 1. 加载
jdbc.properties
- 2. 配置数据库连接池
- 3. 配置SqlSessionFactory对象(使用MyBatis-Spring的情况下)
- 4. 配置扫描Dao接口包,动态实现Dao接口,注入到spring容器中(使用MyBatis-Spring的情况下)
配置数据库连接池----使用spring的数据源
真不愧是企业开发,东西多的我头大。
数据源主要分为三种:不用连接池;在spring中配置并使用连接池;在J2EE容器(比如Tomcat)中通过JNDI配置连接池,在spring中通过JDNI使用连接池。
1. 使用
org.springframework.jdbc.datasource.DriverManagerDataSource
:每有一个连接就新建一个connection,根本没有连接池的作用。<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>2. 使用连接池,比如比较简单的DBCP,使用较多的c3p0,能查看连接池状态的proxool,阿里的druid。
这里用比较简单的DBCP举例,因为官方更新了DBCP2,所以我在这里使用了DBCP2。注意DBCP2的包名是
dbcp2
不是dbcp
,类是org.apache.commons.dbcp2.BasicDataSource
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!--配置初始化的连接数-->
<property name="initialSize" value="0"/>
<!--配置最大连接数。注:maxTotal是版本更新后的名字,以前类似的功能叫maxActive-->
<property name="maxTotal" value="100"/>
<!--配置最大空闲连接数-->
<property name="maxIdle" value="10"/>
<!--配置最小空闲连接数-->
<property name="minIdle" value="0"/>
<!--没有可用连接时的最长等待时间,单位毫秒-->
<property name="maxWaitMillis" value="120000"/>
</bean>3. 使用JNDI作为数据源。类是
org.springframework.jndi.JndiObjectFactoryBean
。<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/DataSourceName"/>
</bean>使用JNDI的话主要的配置就不在spring中,而是在J2EE容器中了。
配置SqlSessionFactory对象
SqlSessionFactory
对象主要将原来SqlMapConfig.xml
中的数据源和扫描mapper.xml
拿了过来,当然既然将SqlSessionFactory
对象交由Spring管理,那么Mybatis的xml配置文件(现在叫mybatis-config.xml
)也要一起配置了。
总之配置信息如下:
<!-- 3.配置SqlSessionFactory对象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
<!--注入Mybatis的配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!--扫描mapper需要的xml配置文件-->
<property name="mapperLocations" value="classpath:mapper/StudentMapper.xml"/>
</bean>
配置扫描Dao接口包
Mybatis能通过Dao
接口+动态代理的技术动态生成Impl。实现Mapper
的注入有MapperFactoryBean
和MapperScannerConfigurer
两个类,前者没添加一个Dao
接口就需要更新一下xml
文件,后者可以自动扫描,所以用自动扫描了。
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入SQLSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!-- 扫描Dao包 -->
<property name="basePackage" value="com.semonx.dao"/>
</bean>
注意:使用MapperScannerConfigurer
时,sqlSessionFactoryBeanName
属性,应该用value
而不是ref
。
编写测试
测试用例完成了:
- 1. 测试获取所有学生
- 2. 测试通过ID查询一个学生
- 3. 测试通过qq查询一个学生
- 4. 测试通过online_id查询一个学生
- 5. 测试CRUD
- 6. 测试CUD的返回值(成功返回true,失败返回false。失败只测试了delete,insert和update不知道如何测失败,直接就抛异常了)
明日计划
加入log4j日志,在服务器上部署一下,应该可以提交了。
问题总结
昨天旧工程遇到的问题:
1. MyBatis的查询测试没有通过,
Student
类的onlineId
成员为空。错误原因:数据库字段使用下划线命名,java使用驼峰命名,
online_id
与onlineId
没有自动映射上。解决方法:在
SqlMapConfig.xml
中开启下划线命名到驼峰命名的自动转换。代码如下:<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>文档对
mapUnderscoreToCamelCase
的解释:mapUnderscoreToCamelCase
:是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。有效值,true | false。默认值false。2. 错误信息:
### Cause: org.apache.ibatis.builder.BuilderException:
Error creating document instance.
Cause: org.xml.sax.SAXParseException; lineNumber: 28; columnNumber: 17;
元素类型为 "configuration" 的内容必须匹配
"(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,
objectWrapperFactory?,reflectorFactory?,plugins?,environments?,
databaseIdProvider?,mappers?)"。错误原因:
SqlMapConfig.xml
中标签的顺序不对引起的错误。解决方案:按照官网文档给出的顺序书写xml文件。官网顺序如下:
新的整合工程遇到的错误
1. 由于缺少
spring-tx
引发的错误错误信息:
java.lang.NoClassDefFoundError: org/springframework/dao/support/DaoSupport
2. 错误原因:缺少
DaoSupport
类。DaoSupport
类在Spring Transaction中。解决方案:添加依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>由于缺少
spring-jdbc
引发的错误错误信息(较长,)
严重: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@edf4efb] to prepare test instance [com.semonx.dao.StudentDaoTest@48aaecc3]
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
...
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in class path resource [spring/spring-dao.xml]: Error setting property values; nested exception is org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'dataSource' threw exception; nested exception is java.lang.NoClassDefFoundError: org/springframework/jdbc/datasource/TransactionAwareDataSourceProxy
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1568)
...
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
... 29 more
Caused by: org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'dataSource' threw exception; nested exception is java.lang.NoClassDefFoundError: org/springframework/jdbc/datasource/TransactionAwareDataSourceProxy
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:121)
...
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1564)
... 45 more错误分析:
首先看
java.lang.IllegalStateException: Failed to load ApplicationContext
,说明是spring加载上下文时出现的错误。再看
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'sqlSessionFactory' defined in class path resource [spring/spring-dao.xml]:
Error setting property values;
nested exception is org.springframework.beans.PropertyBatchUpdateException;
nested PropertyAccessExceptions (1) are:
PropertyAccessException 1:
org.springframework.beans.MethodInvocationException:
Property 'dataSource' threw exception;
nested exception is java.lang.NoClassDefFoundError:
org/springframework/jdbc/datasource/TransactionAwareDataSourceProxy我一层一层找下去,找到最下面,发现是一个
NoClassDefFoundError
,未找到的类是TransactionAwareDataSourceProxy
。百度之,发现是缺少spring-jdbc
。解决方案:添加
spring-jdbc
依赖<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
评论