在项目里面, 我们经常用到 mybatis, 多年前的 hibernate 已经慢慢被大家所抛弃. 自从 iteye 被收购以后, 好久没有写博客了, 今年是要多写一些补一补. 今天来聊一下 mybatis 的 mapper 实现.
- @Component
- public interface ActivityMapper {
- /**
- 添加奖品记录
- @param prizeEntity
- @return
- */
- int addGift(PrizeEntity prizeEntity);
- /**
- * 添加预约记录
- * @param activityPrevueEntity
- * @return
- */
- int addActivityPrevue(ActivityPrevueEntity activityPrevueEntity);
- /**
- * 根据手机号和活动 id 获取该用户是否预约过
- * @param phone
- * @param activityId
- * @return
- */
- int countPrevueByPhoneAndActivityId(@Param("phone")String phone, @Param("activityId")Integer activityId);
- }
这是一个比较常见的 mapper 类的写法. 在 xml 里面我们需要定义一个和方法名一样的 id.
<?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"> http://mybatis.org/dtd/mybatis-3-mapper.dtd ;
- <mapper namespace="cn.vcinema.mapper.ActivityMapper">
- <insert id="addGift" parameterType="cn.vcinema.model.PrizeEntity">
- insert into pumpkin_ius.activity_prize_record(user_id, activity_id, prize_code, create_time)
- values(#{userIdInt}, #{activityIdInt}, #{prizeCodeStr}, now())
- </insert>
- <insert id="addActivityPrevue" parameterType="cn.vcinema.model.ActivityPrevueEntity">
- insert into pumpkin_ius.activity_user_enroll(activity_id, user_id, user_phone, user_name, user_email, create_time)
- values(#{activityId}, #{userId}, #{userPhone}, #{userName}, #{userEmail}, now())
- </insert>
- <select id="countPrevueByPhoneAndActivityId" resultType="java.lang.Integer">
- select count(*) from pumpkin_ius.activity_user_enroll where user_phone = #{phone} and activity_id = #{activityId}
- </select>
- </mapper>
在 serviceimpl 里面, 我们通过调用 mapper 就可以实现 xml 的 sql 执行.
- Gift gift = Lottery.lottery(giftList, defaultGift.get(0));
- PrizeEntity prizeEntity = setPrizeValue(gift, user.getUserId(), activityId);
- // 添加抽奖记录
- activityMapper.addGift(prizeEntity);
需要给 MyBatis 提供 Mapper 接口和与之匹配的映射文件, 就能够让 MyBatis 按照我们的需求执行到对应的 SQL 这里的实现原理就动态代理
- public class MapperProxy<T> implements InvocationHandler, Serializable {
- private static final long serialVersionUID = -6424540398559729838L;
- private final SqlSession sqlSession;
- private final Class<T> mapperInterface;
- private final Map<Method, MapperMethod> methodCache;
- public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
- this.sqlSession = sqlSession;
- this.mapperInterface = mapperInterface;
- this.methodCache = methodCache;
- }
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if(Object.class.equals(method.getDeclaringClass())) {
- return method.invoke(this, args);
- } else {
- MapperMethod mapperMethod = this.cachedMapperMethod(method);
- return mapperMethod.execute(this.sqlSession, args);
- }
- }
- private MapperMethod cachedMapperMethod(Method method) {
- MapperMethod mapperMethod = (MapperMethod)this.methodCache.get(method);
- if(mapperMethod == null) {
- mapperMethod = new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration());
- this.methodCache.put(method, mapperMethod);
- }
- return mapperMethod;
- }
- }
在 invoke 方法中可以看到, 如果我们调用的是 Object 中的方法, 不做任何处理, 直接调用, 否则执行:
mapperMethod.execute(this.sqlSession, args);
这里是用 jdk 的动态代理来实现了自动调用.
在开发的时候, 我们有时候不写 xml , 通过注解的形式直接实现调用, 查看例子.
- @Component
- public interface FeedbackMapper {
- int insert(Feedback feedback);
- /**
- * 添加用户意见反馈
- * @param userFeedback
- */
- @Insert("INSERT INTO `pumpkin_ius`.`user_feedback`(`phone`, `device`, `pc_device`, `pc_os`, `pc_channel`, `pc_ip`, `pc_platform`, `pc_version`, `pc_browser_name`, `pc_browser_version`, `play_feedback`, `program_feedback`, `other_feedback`) VALUES (#{phone},#{device},#{pc_device},#{pc_os},#{pc_channel},#{pc_ip},#{pc_platform},#{pc_version},#{pc_browser_name},#{pc_browser_version},#{play_feedback},#{program_feedback},#{other_feedback});")
- void addUserFeedback(UserFeedback userFeedback);
- }
当然, 在 SQL 复杂的时候, 还是写 xml 比较方便维护, 看起来不那么难受.
来源: http://www.bubuko.com/infodetail-3066624.html