发表于: 2017-04-30 14:42:45

1 1324


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. 1. 加载jdbc.properties
  2. 2. 配置数据库连接池
  3. 3. 配置SqlSessionFactory对象(使用MyBatis-Spring的情况下)
  4. 4. 配置扫描Dao接口包,动态实现Dao接口,注入到spring容器中(使用MyBatis-Spring的情况下)

配置数据库连接池----使用spring的数据源

真不愧是企业开发,东西多的我头大。

数据源主要分为三种:不用连接池;在spring中配置并使用连接池;在J2EE容器(比如Tomcat)中通过JNDI配置连接池,在spring中通过JDNI使用连接池。

  1. 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. 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. 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的注入有MapperFactoryBeanMapperScannerConfigurer两个类,前者没添加一个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. 1. 测试获取所有学生
  2. 2. 测试通过ID查询一个学生
  3. 3. 测试通过qq查询一个学生
  4. 4. 测试通过online_id查询一个学生
  5. 5. 测试CRUD
  6. 6. 测试CUD的返回值(成功返回true,失败返回false。失败只测试了delete,insert和update不知道如何测失败,直接就抛异常了)

明日计划

加入log4j日志,在服务器上部署一下,应该可以提交了。

问题总结

昨天旧工程遇到的问题:

  1. 1. MyBatis的查询测试没有通过,Student类的onlineId成员为空。

    错误原因:数据库字段使用下划线命名,java使用驼峰命名,online_idonlineId没有自动映射上。

    解决方法:在SqlMapConfig.xml中开启下划线命名到驼峰命名的自动转换。代码如下:

    <settings>
       <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    文档对mapUnderscoreToCamelCase的解释:

    mapUnderscoreToCamelCase:是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。有效值,true | false。默认值false。

  2. 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文件。官网顺序如下:

    mybatis配置的标签顺序

新的整合工程遇到的错误

  1. 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>
  2. 由于缺少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>



返回列表 返回列表
评论

    分享到