目录
第一部分:基本配置内容
首先创建一个最简单的maven webapp项目,web.xml文件中需要添加的内容如下,用于引入SpringMVC以及Spring
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</context-param>
<servlet>
<servlet-name>mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
然后添加Spring+SpringMVC+mybatis对应的配置文件
首先是Spring.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.zk.demo" />
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<array>
<value>classpath:datasource.properties</value>
</array>
</property>
</bean>
<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>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:mappers/*.xml"></property>
<property name="configLocation" value="classpath:spring-mybatis.xml"></property>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.zk.demo.mapper" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<aop:config>
<aop:pointcut id="targetMethod" expression="execution(* com.zk.demo.service.*.*(..))" />
<aop:advisor pointcut-ref="targetMethod" advice-ref="transactionAdvice"/>
</aop:config>
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
<tx:method name="*" propagation="REQUIRED" read-only="true"/>
</tx:attributes>
</tx:advice>
</beans>
然后是SpringMVC对应的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<mvc:annotation-driven/>
<context:component-scan base-package="com.zk.demo.controller" />
</beans>
最后是mybatis配置文件
<?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="aggressiveLazyLoading" value="false"/>
<setting name="cacheEnabled" value="true"/>
<setting name="logImpl" value="SLF4J" />
</settings>
<typeHandlers>
<package name=""/>
</typeHandlers>
<databaseIdProvider type="DB_VENDOR">
<property name="SQL SERVER" value="sqlserver"/>
<property name="Oracle" value="oracle"/>
<property name="MYSQL" value="mysql"/>
</databaseIdProvider>
</configuration>
中心思想:Spring中配置了myabtis配置文件位置和mapper文件所在位置(mybatis配置文件配置比较死板),数据源交给spring 管理,因为涉及到了事务,mybatis配置文件只是负责其他mybatis就好了比如全局设置,类型转换设置,还有一个比较重要的就是数据库类型设置,目前使用比较多的关系型数据库就是mysql oracle sqlserver这三类,我打算都兼容下,作为练习吧,毕竟公司换数据库的情况还不是很多,有的时候大家写sql通常只会兼容一种数据库,具体的下面再说。
Mapper接口使用的MapperScanConfigure自动扫描,同时mapper接口需要添加@Mapper注解,实体类别名需要使用@Alias注解
第二部分:Mapper文件基本语法
配置完以上内容基本上就能跑起来了,但是mybatis还有一个比较重要的配置就是SQL映射文件mapper.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.zk.demo.mapper.DatabaseHealthMapper">
<select id="isAlive" resultType="Integer" databaseId="mysql">
SELECT COUNT(*)
FROM DUAL
</select>
</mapper>
mapper标签的namespace很重要。对应的是Java的接口路径,下面就是增删改查的各种标签了
select标签
基本的标签属性就不讲解了id resultType resultMap 这些的,其中比较特殊的是resultMap这个标签
里面可以添加association collection discriminator(根据结果值来判定使用哪个映射) case某些值的结果映射(这些后面讲)。
另外rsultMap的result字标签还可以添加typeHandler内容
insert标签
标签内容不常用的如
flushCache 清空一级一级二级缓存,这个默认就是true可以不用关注
timeout指的是驱动程序等待数据库的响应时间,单位是秒
statementType:包含三种类型Statement prepared callable默认是prepared
useGeneratedKeys:默认是false,如果是true的话会调用JDBC的getGeneratedkeys(),不是所有的数据库都支持主键自增的,oracle就是使用的序列。
databseId是用来区分数据库的,如果都存在,没有标注databaseId的将被胡略
update以及delete标签就没啥新鲜的了。
第三部分:动态SQL标签的使用
if标签
<if test="userName!=null and userName!=''">
</if>
choose标签
<choose>
<when test="id!=null">
</when>
<otherwise>
</otherwise>
</choose>
where set trim标签
咋说呢,where和set标签都是trim标签的一种具体简化,换句话说就是where标签和set标签都可以用trim实现
where和set标签会自动去掉相应位置的 and 逗号之类的
foreach标签
foreach可以处理三种集合 list array map
<foreach collection="list" open="(" close=")" separator="," item="item">
</foreach>
以下是map轮询
<foreach collection="_parameter.keys" item="key" open="(" close=")" separator="," >
${key}
</foreach>
values
<foreach collection="_parameter.keys" item="key" open="(" close=")" separator=",">
#{params[${key}]}
</foreach>
<foreach collection="_parameter" index="key" item="value" separator=",">
</foreach>
bind标签
做这个标签就是定义一个变量<bind name="" value=""/>
这样下面就可以使用#{name}作为数据了
注意collection的值,当列表的时候填写list数组的时候填写array map的时候需要填写_parameter 但是如果使用了@param注解则需要填写对应的名称
第四部分:Mybatis高级映射查询
可以使用mybatis ognl表达式实现自动映射,也可以通过下面的配置实现映射。
一对一映射association
直接将字段值根据ognl表达式绑定到对应的字段上。
<resultMap type="" id="">
<association property="role" resultMap="com.zk.demo.mapper.RoleMapper.roleMap" columnPrefix="role_"/>
<association property="role" resultMap="com.zk.demo.mapper.RoleMapper.roleMap" select="" column="{id=role_id}"/>
</resultMap>
一对多映射collection配置内容和association是一样的
鉴别器映射(discriminator),类似于switch这么个东西,这个标签有column javaType两个属性,这个标签有多个case子标签,
子标签包含value resultType resultmap三个属性。
不太建议用这个东西,感觉业务逻辑被写到了sql中,以后变化是个问题。
第五部分:Mybatis存储过程调用
<select id="" statementType="CALLABLE" useCache="false">
{
call select_power(
#{id,mode=IN}
)
}
</select>
存储过程需要加上statementType="CALLABLE",另外存储过程不支持二级缓存,因此需要加上userCache=false
另外mode=OUT的参数都需要指定jdbcType,如果入参可能存在null的情况,则也需要提供jdbcType
数据库类型BLOB对应java的byte[],但是这时候java可能默认的是byte类型,因此遇到这种情况还需要指定javaType
带有游标的存储过程(Mysql不支持游标参数 oracle支持)
使用游标需要将jdbcType设置为CURSOR javaType设置为ResultSet,结果是一个多列的内容,需要resultMap映射
{
call select_cuscor(
#{list,mode=OUT,jdbcType=CUSCOR,javaType=ResultSet,resultMap=}
)
}
注意其中的list是看响应的结果内容是什么,其实不太建议使用游标,毕竟不是所有的数据库都支持。
通过枚举实现,首先需要添加对应的TypeHandler,然后再Mybatis配置文件中加上转换器扫描就可以了。
第六部分:Mybatis缓存配置
Mybatis默认开启一级缓存,一级缓存指的是一次会话之中的请求会缓存,二级缓存指的是整个项目启动过程中会是缓存。
如果想避免一级缓存导致的问题可以在查询sql的时候设置select 标签中的flushCache=true,实际上使用的时候如果你在controller连续两次调用service在调用mapper你会发现还是重复查询两次数据库,但是在service中重复调用mapper你就会发现只会调用一次数据库,这是由差别的。另外每次执行insert update delete都会清除一级缓存。
二级缓存配置首先需要在Mybatis配置文件中添加
<setting name="cacheEnabled" value="true"/>
然后需要在对应的mapper.xml配置文件中添加
<cache eviction="LRU" flushInterval="60000" size="1024" readOnly="true"/>
非只读的缓存每次响应的时候会通过序列化响应缓存内容的副本,Mybatis默认使用的缓存是基于Map的缓存,同样可以集成其他的缓存框架。
使用ehcache缓存框架,分布式缓存,并且支持内存硬盘双模式
首先需要添加对应的依赖,然后添加ehcache.xml配置文件
pom.xml添加
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
</dependency>
ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false"
monitoring="autodetect"
dynamicConfig="true">
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="20000"
eternal="false"
copyOnRead="true"
copyOnWrite="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskPersistent="false"
/>
</ehcache>
最后需要在Mapper.xml文件中添加
<cache type="org.springframework.cache.ehcache.EhCacheCache"./>
使用redis实现二级缓存
需要添加对jedis的支持以及mybatis-redis支持
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-redis</artifactId>
</dependency>
然后添加mybatis-redis配置文件redis.properties
host=127.0.0.1
port=6379
password=
connectionTimeout=5000
soTimeout=5000
database=
clientName=
最后修改mapper.xml中的内容
<cache type="org.mybatis.caches.redis.RedisCache"/>
另外多表查询的时候有可能会产生脏数据,因为他们的命名空间是不一样的,因此一个命名空间内容修改了并不能更新另一个命名空间的缓存,因此会产生脏数据。
第七部分:细节注意事项
1.主键自增
如果数据库支持主键自增
<!-- 主键联合索引需要设置keuColume="key1,key2" 同样keyproperty -->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
</insert>
如果数据库不支持主键自增
<!-- mysql是AFTER oracle是before 因为支持主键自增的都是插入完了以后才能获取到主键,不支持主键自增的,需要先查询序列因此是before -->
<selectKey keyProperty="id" keyColumn="id" order="AFTER" resultType="long">
</selectKey>
selectKey是用来获取主键的,当批量向oracle这种只能通过查询序列获取主键的时候可以这样使用
<selectkey>
</selectKey>
insert XXX
foreach的形式就可以了。
2.为了防止HTTP请求中的数据有啥编码问题,加入如下内容
<filter>
<filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
3.目前mybatis可以自动区分出来参数的内容,因此所有的标签parameterType可以不用配置
4.数据库datetime类型的字段可以保存date timestamp两种类型的数据,但是没办法保存time数据
5.写参数的时候直接在接口Mapper上面使用@Param注解,会自动创建Map的。
6.${value}这种东西不能避免SQL注入
第八部分:附录
1.项目依赖打算使用Maven
2.数据库使用Mysql
3.使用SpringMVC4+spring4+mybatis3整合的形式运行代码
4.JDK我要求至少1.7,我家里用的10
本文章不推荐将SQL语句注解到Java类的mapper接口上去,不想修改一个sql还要重新编译一遍,思想是Xml配置+注解,我也不打算讲解代码生成器那些东西,我知道Mybatis有响应的插件,因为以后维护起来可能会比较麻烦。