mybatis直接与数据库交互,实现了数据操作层,对数据库的操作主要有:增加、删除、更改、查询以及存储过程调用等操作。
一、数据操纵(增、删、改、查)
1、新增数据、更改数据传递的参数均为记录类型,mapper配置文件内容如下:
<insert id="insert" parameterType="com.springmvc.entity.SUser" >
<!--
WARNING - @mbggenerated
This element is automatically generated by MyBatis Generator, do not modify.
This element was generated on Wed Jan 17 11:25:43 CST 2018.
-->
<!--表示插入之后查询相应的插入数据,无需实现相应操作时可删除-->
<selectKey resultType="java.lang.String" keyProperty="personid" order="AFTER" >
SELECT SCOPE_IDENTITY()
</selectKey>
insert into S_USER (LOGINNAME, PASSWORD, UNTID, ROLEID)
values (#{loginname,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}, #{untid,jdbcType=VARCHAR},
#{roleid,jdbcType=CHAR})
</insert>
<update id="updateUser" parameterType="com.springmvc.entity.SUser">
update S_USER set LOGINNAME=#{loginname,jdbcType=VARCHAR},PASSWORD=#{password,jdbcType=VARCHAR},UNTID=#{untid,jdbcType=VARCHAR},ROLEID=#{roleid,jdbcType=CHAR} WHERE PERSONID = #{personid,jdbcType=VARCHAR}
</update>
2、删除数据
3、一般数据查询
4、复杂查询
mybatis复杂 查询sql主要有一下几类:
1)、通过if判断动态组织sql;
<select id="findActiveBlogLike" resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<!--通过条件判断动态生成sql-->
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
2)、通过choose (when,otherwize) (相当于java 语言中的 switch ,与 jstl 中的choose 很类似)动态组织sql;
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <choose> <when test="title != null"> AND title like #{title} </when> <when test="author != null and author.name != null"> AND author_name like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose> </select>
3)、trim前缀、后缀组织复杂sql;
<select id="getUsertList_if_trim" resultMap="resultMap_User"> SELECT * FROM user u <!--使用trim能够有效避免在依次进行条件判断,组合查询条件时出现where后无条件或者where 后直接连接 and符合等问题--> <!--有trim根据是否有条件确定是否在查询中增加where,也根据条件组合情况自动添加 条件连接符号(and 或者 or)--> <trim prefix="WHERE" prefixOverrides="AND|OR"> <if test="username !=null "> u.username LIKE CONCAT(CONCAT('%', #{username, jdbcType=VARCHAR}),'%') </if> <if test="sex != null and sex != '' "> AND u.sex = #{sex, jdbcType=INTEGER} </if> <if test="birthday != null "> AND u.birthday = #{birthday, jdbcType=DATE} </if> </trim> </select> <!--trim还可以用于update中,以动态生成数据更改内容和条件-->
<update id="updateUser_if_trim" parameterType="com.yiibai.pojo.User"> UPDATE user <trim prefix="SET" suffixOverrides=","> <if test="username != null and username != '' "> username = #{username}, </if> <if test="sex != null and sex != '' "> sex = #{sex}, </if> <if test="birthday != null "> birthday = #{birthday}, </if> </trim> WHERE user_id = #{user_id} </update>
4)、foreach组织复杂sql;
oreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。
foreach元素的属性主要有 item,index,collection,open,separator,close。
item表示集合中每一个元素进行迭代时的别名,
index指 定一个名字,用于表示在迭代过程中,每次迭代到的位置,
open表示该语句以什么开始,
separator表示在每次进行迭代之间以什么符号作为分隔 符,
close表示以什么结束。
在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况 下,该属性的值是不一样的,主要有一下3种情况:
1. 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
2. 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
3. 如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在breast里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key 下面分别来看看上述三种情况的示例代码:
<select id="dynamicForeachTest" parameterType="java.util.List" resultType="Blog"> select * from t_blog where id in <foreach collection="list" index="index" item="item" open="(" separator="," close=")"> #{item} </foreach> </select> 其中list是调用dynamicForeachTest方法时需要传递的调用参数,当参数类型是"java.util.List"时传递list对象;为array时传递数组对象;否则传递每个元素对象类型为Map的list或arra
二、mybatis调用存储过程(特别复杂的查询完全可以通过存储过程实现,然后通过mybatis调用存储过程)
假设在数据库中以编写了存储过程:SP_MF_I_IMP;该存储过程的调用参数:
I_MANIFEST_I_ID IN NUMBER ,
I_FUNCTION_CODE IN VARCHAR2,
I_FIRM_ID IN NUMBER, I_OP_USER IN VARCHAR2, --操作人ID O_RETURN_MESSAGE OUT VARCHAR2
四个输入参数,一个输出参数;该存储过程执行成功后将返回类型为string的提示信息;该存储过程的xml配置信息如下:
<parameterMap id="sendMap" type="java.util.HashMap">
<parameter property="I_MANIFEST_I_ID" jdbcType="NUMERIC" javaType="java.lang.Long" mode="IN"/>
<parameter property="I_FUNCTION_CODE" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/>
<parameter property="I_FIRM_ID" jdbcType="NUMERIC" javaType="java.lang.Integer" mode="IN"/>
<parameter property="I_OP_USER" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/>
<parameter property="O_RETURN_MESSAGE" jdbcType="VARCHAR" javaType="java.lang.String" mode="OUT"/>
</parameterMap>
<update id="sendManifstmanToEdi" parameterMap="sendMap" statementType="CALLABLE">
<![CDATA[
{call SP_MF_I_IMP(?, ?, ?, ?, ?)}
]]>
</update>
需依据调用参数定义相应的hashmap类型
Map<String,Object> params = new HashMap<String, Object>();
try {
params.put("I_MANIFEST_I_ID", id);
params.put("I_FUNCTION_CODE", Constants.MAINIFEST_DECLARE);
params.put("I_FIRM_ID", getFirmOfLoginUser().getFirmId());
params.put("I_OP_USER", getLoginUser().getLoginName());
params.put("O_RETURN_MESSAGE", "");
manifestIMainService.sendManifstmanToEdi(params);
result = String.valueOf(params.get("O_RETURN_MESSAGE"));
} catch (Exception e) {
log.error("sendEdi occurred error.", e);
if(Constants.IS_TEST)
setErrorMsg(e.getMessage());
}
return result;
当通过存储过程执行查询操作,返回打开的游标结果集时,需根据打开的游标集字段名称和类型,定义结果集,配置文件如下:
<resultMap id="flowLogsResultMap" type="com.hwt.glmf.log.vo.FlowLogModel">
<result column="ID" property="id" />
<result column="STATUS" property="status" />
<result column="OP_USER" property="op_user" />
<result column="OP_TIME" property="op_time" />
<result column="BILL_NO" property="bill_no" />
<result column="TRAN_NO" property="tran_no" />
<result column="MEMO" property="memo" />
<result column="DATA_TYPE" property="data_type" />
</resultMap>
<!-- jdbcType=INTEGER ORACLE:INT-->
<select id="viewFlowLog" parameterType="java.util.Map" statementType="CALLABLE">
<![CDATA[
{call SP_TRACE_GET(#{I_DATA_TYPE,mode=IN,jdbcType=VARCHAR},
#{I_TRAN_NO,mode=IN,jdbcType=VARCHAR},#{I_BILL_NO,mode=IN,jdbcType=NUMERIC},
#{O_LIST,mode=OUT,jdbcType=CURSOR,javaType=java.sql.ResultSet,resultMap=flowLogsResultMap})}
]]>
</select>
其中:#{I_DATA_TYPE,mode=IN,jdbcType=VARCHAR}, #{I_TRAN_NO,mode=IN,jdbcType=VARCHAR},#{I_BILL_NO,mode=IN,jdbcType=NUMERIC}为调用存储过程输入参数的名称和类型,
#{O_LIST,mode=OUT,jdbcType=CURSOR,javaType=java.sql.ResultSet,resultMap=flowLogsResultMap}为打开游标输出的结果集
待用存储过程的代码如下:
public List<FlowLogModel> viewFlowLog(String dataType, String tran_no,
String bill_no) throws Exception {
Map<String, Object> param = new HashMap<String, Object>();
param.put("I_DATA_TYPE", dataType);
param.put("I_TRAN_NO", tran_no);
param.put("I_BILL_NO", bill_no);
param.put("O_LIST", OracleTypes.CURSOR);
flowLogDao.viewFlowLog(param);
return (List<FlowLogModel>)param.get("O_LIST");
}
关于mybatis访问存储过程可参见http://blog.csdn.net/wangchangpen62/article/details/44961983
三、mybatis事务处理
集成了spring的mybatis一般在spring的mybatis配置文件中定义事务管理器,一般采用将mybatis参与到spring事务的方法进行事务处理;
1、配置文件加载顺序:spring+mvc+mybatis开发中一般会涉及到applicationContext.xml、mybatis.xml以及spring-mvc.xml几个配置文件;一般情况下在web.xml中首先定义
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
即:上下文监听器,以保证webApplicationContext能够自动创建持久层实现对象(即自动创建Dao接口相应对象,开发中无需实现该接口代码),然后创建通过context-param参数装载的applicationContext.xml、mybatis.xml配置文件;
在加载mybatis-context.xml时,若在mybatis.xml文件中定义了与业务和路由控制相关对象,Spring就会装配@Controlle和@Service的容器,并把他们放到Spring的容器中来;接着加载spring-mvc.xml,若在spring-mvc.xml文件中也定义了Cotroller、Service对象,这时Spring也会把@Service和@Controller注解的实例装配到Spring容器中,但是这时由于先前在加载mybatis-context.xml时已经装配过@Service和@Controller的容器,所以这时新装配的容器会覆盖掉先前的容器,所以Spring容器中就只剩下后来装配的容器了。
@Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
public void saveUser(User u) throws Exception{
userMapper.insert(u);
throw new Exception("hehe");
}
注意:执行方法异常时需要回滚事务,需要设置@Transactional的属性rolllbackFor=Exception.class,即异常时回滚事务。
2、注解式的事务处理方法:
@Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。
虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。
事务注解的详细介绍参见:
https://www.cnblogs.com/yepei/p/4716112.html