zoukankan      html  css  js  c++  java
  • 乱入Spring+Mybatis

      新进入一个项目,写了一个功能,就是提供一个服务(service),该服务能够查询和插入。完成后,想要用junit测试一下;发现到了DAO底层注入的SqlSession字段为空;才意识到这是一个Spring注解的项目;之前经验主要是Spring MVC方式开发使用到Spring的注解和依赖注入。另外,这个字段被注解为@Autowired(required=true),在编译器都没有被报错实例化失败,也说明了以着这种测试的方式根本就没有走Spring的容器来管理对象。

      看来是时候要好好研究一下Spring和Mybatis的一些功能本质。

      想要在非Web工程使用Spring,那么需要通过于是添加了applicationContext.xml,定义了服务类bean,然后通过下面的方式获取容器获取对象:

    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");// 读取bean.xml中的内容
    SmallServiceImplsvr = ctx.getBean("service", SmallServiceImpl.class);// 创建bean的引用对象

      Spring的思想就是容器管理bean,所以无论是他和谁组合,还是让他管理什么,都是向Spring的容器中放入对象。那么,这种放入就有了很多种方式,一种是通过向配置文件中添加配置的传统方式,比如,下面就是添加了service的引用。

    <?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.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
        <context:annotation-config />
        <context:component-scan
            base-package="com.a.b.component, com.a.b.service, com.a.b.dao" />
        <bean id="service" class="com.a.b.service.impl.SmallServiceImpl"></bean>
    </beans>

      定义了bean就可以通过上面的代码来获取SmallServiceImpl了。但是对于这段xml有两点说明:

      1. 其实是不需要对annotation-config进行声明,因为component-scan已经具有了annotation-config的职能;

      2.component-scan可以一次性声明扫描多个包(Spring做的扫描是扫描class文件);我就是曾经有一次运行报错,就是因为有一个包没有添加到监视,导致了Spring容器创建bean失败;

      扫描的本质是基于注解(@Service,@Component,@Repository)来发现bean(免于在xml文件进行配置),扫描之后,就是“装配”,类似于Autowired声明是为了Spring容器在实例化bean的过程中来装配字段,所以扫描和装配是两个阶段,后者是基于前者,也不完全依赖(还可以基于配置文件)。

      你会发现一个现象:@Autowired声明的字段的类型都是接口,但是作为装配的类都是通过@Service/@Repository注解声明的实现类。

      另外对于基于注解的说明,对于本例而言,可以不再配置文件中声明service,可以在定义的类头声明@Service(value="service")也可;如果不指定value值,默认的bean的名称为类名首字母小写(smallServiceImp)

    @Service(value="service")
    public class SmallServiceImpl {

      通过getBean获取到了SmallService之后,在运行发现还是报错,因为执行到DAO的时候,发现那个SqlSession的字段(required=true)实例化失败,无法找到候选类;查找了很久原因;其实扫描的是指定的包,无法找到mybaits的类很正常,这个时候就是第三段那段话,和第三方组件配合的时候,第三方组件都是以bean形式定义到了Spring中;另外这个问题查了一段时间是因为我忘记了MyBatis的核心组件就是SqlSession以及SqlSessionFactory,早点想到就能知道需要将其以bean形式注入。

        <bean id="dataSource" name="dataSource"
            class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <!-- 指定连接数据库的驱动 -->
            <property name="driverClass" value="dm.jdbc.driver.DmDriver" />
            <!-- 指定连接数据库的URL -->
            <property name="jdbcUrl" value="jdbc:dm://localhost:5236" />
            <!-- 指定连接数据库的用户名 -->
            <property name="user" value="user" />
            <!-- 指定连接数据库的密码 -->
            <property name="password" value="password" />
            <!-- 指定连接池中保留的最大连接数. Default:15 -->
            <property name="maxPoolSize" value="10" />
            <!-- 指定连接池中保留的最小连接数 -->
            <property name="minPoolSize" value="3" />
            <!-- 指定连接池的初始化连接数 取值应在minPoolSize 与 maxPoolSize 之间.Default:3 -->
            <property name="initialPoolSize" value="3" />
            <!-- 最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。 Default:0 -->
            <property name="maxIdleTime" value="0" />
            <!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数. Default:3 -->
            <property name="acquireIncrement" value="2" />
            <!-- JDBC的标准,用以控制数据源内加载的PreparedStatements数量。 但由于预缓存的statements属于单个connection而不是整个连接池所以设置这个参数需要考虑到多方面的因数.如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default:0 -->
            <property name="maxStatements" value="20" />
            <!-- 每60秒检查所有连接池中的空闲连接.Default:0 -->
            <property name="idleConnectionTestPeriod" value="60" />
        </bean>
    
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <property name="configLocation" value="classpath:sqlmapConfig.xml"></property>
            <property name="mapperLocations" value="classpath:mapper/*Mapper.xml"></property>
            <property name="typeAliasesPackage" value="com.a.b.vo"></property>
        </bean>
    
        <!-- 配置SQLSession模板 -->
        <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
            <constructor-arg index="0" ref="sqlSessionFactory" />
        </bean>

      增加了三个bean,定义数据源(dataSource),定义SqlSessionFactory以及SqlSession就不多说什么了。核心就是SqlSessionFactory,dataSource字段说明了数据源信息(此次项目使用的ComboPooledDataSource进行JDBC以及连接池管理);mapperLocation,就是告知mapper文件路径,注意这里路径指的是class路径,因为Spring容器的操作都是在部署之后的环境,所以一定是claas路径;configLocation,对于mybatis的配置(比如mapper参数对象,返回对象的别名,mybatis对于缓存的一些配置都是放置在这个配置文件中;至于typeAliasesPackage,不知。

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <settings>
            <setting name="cacheEnabled" value="true" />
            <setting name="lazyLoadingEnabled" value="true" />
            <setting name="aggressiveLazyLoading" value="false" />
            <setting name="multipleResultSetsEnabled" value="true" />
            <setting name="useColumnLabel" value="true" />
            <setting name="defaultExecutorType" value="REUSE" />
            <setting name="defaultStatementTimeout" value="25000" />
        </settings>
    
        <typeAliases>
            <package name="com.zcm.mall.vo"/>
        </typeAliases>
    
    </configuration>

      上面这个就是mybatis的配置文件。

      配置好了SqlSession/Factory信息之后,SqlSession字段可以被实例化,而且可以顺利的访问数据库了。

    小记

      1. 在mapper文件中,经常会有比较大小的情况">","<",对于这些特殊字符要么采用转义的方式,要么采用<![CDATA[ 这里写你的sql ]]>  这种方式;

      2.在mapper的sql中,可以通过在sql语句中添加<include refid="whereClause" />来添加共通的sql,比如where的过来条件(根据查询bean字段进行拼sql),可能多个select语句会共用,这个时候可以考虑使用。比如分页是一个共同的sql,可以单独放置到一个文件中(比如CommonsqlMapper.xml),然后使用的地方通过include进行引用。

    CommonSqlMapper.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="commonSql" >
      <sql id="pageSql">
        <if test="offset != null and limit != null">
          limit #{offset}, #{limit}
        </if>
      </sql>
    </mapper>

    ASqlMapper.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.zcm.mall.vo.AuditLog">
        <resultMap id="auditLog" type="com.a.b.vo.c">
            <id column="id" property="id" jdbcType="BIGINT" />
            <result column="log_type" property="logType" jdbcType="VARCHAR" />
            <result column="log_msg" property="log" jdbcType="VARCHAR" />
            <result column="oper_Id" property="userId" jdbcType="BIGINT" />
            <result column="oper_name" property="userName" jdbcType="VARCHAR" />
            <result column="create_date" property="createDate" jdbcType="VARCHAR" />
        </resultMap>
        <select id="select" parameterType="auditLog" resultMap="auditLog">
            select * from AUDIT_LOG
            <include refid="whereClause" />
            <include refid="commonSql.pageSql" />
        </select>

      上面的xml中有一个地方定义了resultMap,这个定义用于将数据库中查询结果和实体类进行映射之用。如果你的数据库字段定义的和实体类名称不一致,需要通过这种方式进行映射。

  • 相关阅读:
    我心飞翔
    又见草堂
    有一种爱只能用心去珍藏《转贴》
    人事管理制度(爆笑)
    廊桥放歌
    记住: 惰性,职业生涯的无形杀手
    职场“三无人员”如何突破自己
    升职“流产”,都是谦虚惹的祸(转)
    李嘉诚让员工忠诚的简单办法
    尤未尽意
  • 原文地址:https://www.cnblogs.com/xiashiwendao/p/6599403.html
Copyright © 2011-2022 走看看