文章目录
1. ${} 和 #{}的区别
Mybatis中的#{}用于传递查询的参数,用于从dao层传递一个string参数过来(也可以是其他参数),select * from 表名 order by age=#{age}
Mybatis会把这个参数转换成一个字符串。select * from 表名 order by age=“age” 相当于jdbc中的预编译,安全。
${}一般用于order by的后面,Mybatis不会对这个参数进行任何的处理,直接生成了sql语句。例:传入一个年龄age的参数,select * from 表名 order by ${age}
所以首选使用 #{}
但是传递参数为一个以上的时候,需要我们用注解去绑定参数
通过使用 @Param注解的方式(org.apache.ibatis.annotations.Param)
@Select("select * from seckill order by create_time desc limit #{offset},#{limit}")
List<Seckill> queryAll(@Param("offset")int offset,@Param("limit")int limit);
2. 传递参数
2.1 第一种
通过#{0},#{1} 方式,#{0} 代码第一个参数,#{1} 代码第二个参数
public Good selectGood(String id, String name);
xml
<select id="selectGood" resultMap="GoodMap">
select * from good where id = #{0} and name=#{1}
</select>
2.2 第二种
通过固定参数的方式
java
public Good selectGood(@param("id")String id,@param("name")String name);
xml
<select id="selectGood" resultMap="GoodMap">
select * from good where id = #{id} and name=#{name}
</select>
2.3 第三种
通过Map集合去传递(推荐)
java
public Good selectGood(){
Map map = new HashMap();
map.put("id",1);
map.put("name","pibigstar");
Good good = goodService.selectGood(map);
return good;
}
xml
<select id="selectGood" resultMap="GoodMap">
select * from good where id = #{id} and name=#{name}
</select>
3. 开启驼峰命名规范
//在application.properties中设置
mybatis.configuration.map-underscore-to-camel-case=true //开启驼峰命名
如果不设置需要手动在查询的时候设置:
@Select("select * from seckill")
@Results({
//如果不开启驼峰命名,就要手动这样设置
@Result(property="seckillId",column="seckill_id"),
@Result(property="createTime",column="create_time"),
@Result(property="startTime",column="start_time"),
@Result(property="endTime",column="end_time"),
})
List<Seckill> list();
4. 设置扫描包路径
//application.properties中设置
mybatis.type-aliases-package=com.pibigstar.domain
如果不设置可以在启动类中手动设置
@SpringBootApplication
@MapperScan("com.pibigstar.mapper")
public class SeckillApplication{
public static void main(String[] args) {
SpringApplication.run(SeckillApplication.class, args);
}
}
5. 联表查询
/**
* 根据id拿到SuccessSeckilled并携带秒杀商品的对象
* @param seckillId
* @return
*/
@Select("select sk.seckill_id,sk.user_phone,sk.create_time,sk.state,"
+ " s.seckill_id 'seckill.seckill_id',s.name 'seckill.name',s.number 'seckill.number',s.create_time 'seckill.create_time',s.start_time 'seckill.start_time',s.end_time 'seckill.end_time'"
+ " from success_killed sk inner join seckill s on sk.seckill_id=s.seckill_id "
+ " where sk.seckill_id=#{seckillId} and sk.user_phone=#{userPhone}")
SuccessKilled queryByIdWithSeckill(@Param("seckillId")long seckillId,@Param("userPhone")long userPhone);
6. 事务
事务方法的执行时间要尽可能短,不要穿插一些网络操作(RPC/HTTP)请求,如果必须需要,那么将这些网络操作剥离出来(定义一个网络操作方法,将拿到的数据再传递给此事务方法)
不是所有的方法都需要事务,比如: 只有一条修改操作,或只有 只读操作
一般都是读操作和写操作要在同一个方法中时需要申明事务
6.1 添加事务
- 在xml中配置
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="mySessionFactory"/>
</property>
</bean>
<!-- 配置事务传播特性 -->
<tx:advice id="TestAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="del*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="add*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置参与事务的类 -->
<aop:config>
<aop:pointcut id="allTestServiceMethod" expression="execution(* com.test.testAda.test.model.service.*.*(..))"/>
<aop:advisor pointcut-ref="allTestServiceMethod" advice-ref="TestAdvice" />
</aop:config>
- 在方法中添加注解
@Transactional
@Transactional
public SeckillExecution executeSeckill(long seckillId, long userPhone, String md5)
throws SeckillException, RepeatkillException, SeckillCloseException {
if (md5==null||!md5.equals(MD5Util.getMD5(seckillId))) {
throw new SeckillException("MD5值不合法");
}
try {
//执行秒杀,减少库存
Date nowTime = new Date();
int updateCount = seckillMapper.reduceNumber(seckillId, nowTime);
if (updateCount<=0) {
//没有更新到记录,秒杀结束
throw new SeckillCloseException("秒杀结束");
}else {
//记录购买行为
int insertCount = successKilledMapper.insert(seckillId, userPhone);
if (insertCount<=0) {
//重复插入(主键为seckill和userphone联合主键)
//返回0,重复秒杀
throw new RepeatkillException("重复秒杀");
}else {
//返回1,秒杀成功
SuccessKilled successKilled = successKilledMapper.queryByIdWithSeckill(seckillId, userPhone);
return new SeckillExecution(seckillId, SeckillStateEnum.SUCCESS,successKilled);
}
}
}catch (SeckillCloseException e1) {
throw e1;
}catch (RepeatkillException e2) {
throw e2;
}
catch (Exception e) {
logger.error(e.getMessage(),e);
//所有编译期异常 转换为了运行期异常
throw new SeckillException("seckill inner error:"+e.getMessage());
}
}
6.2 事务回滚
spring默认当方法抛出运行期异常的时候会回滚事务
所以我们一般要将编译期异常转化为运行期异常
@Override
@Transactional
public SeckillExecution executeSeckill(long seckillId, long userPhone, String md5)
throws SeckillException, RepeatkillException, SeckillCloseException {
if (md5==null||!md5.equals(MD5Util.getMD5(seckillId))) {
throw new SeckillException("MD5值不合法");
}
try {
//执行秒杀,减少库存
Date nowTime = new Date();
int updateCount = seckillMapper.reduceNumber(seckillId, nowTime);
}
catch (Exception e) {
logger.error(e.getMessage(),e);
//将所有编译期异常 转换为了运行期异常
throw new SeckillException("seckill inner error:"+e.getMessage());
}
SeckillException是我们自定义的运行期异常,主要是处理各种业务异常
package com.pibigstar.exception;
/**
* 秒杀相关业务异常
* @author pibigstar
*/
public class SeckillException extends RuntimeException{
private static final long serialVersionUID = 1L;
public SeckillException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public SeckillException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
}
7. 插入返回主键
- 第一种:
加入这两个属性:useGeneratedKeys="true" keyProperty="id"
<insert id="insert" useGeneratedKeys="true" keyProperty="id" parameterType="com.pibigstar.User">
insert into user(userName,password,comment)
values(#{userName},#{password},#{comment})
</insert>
- 第二种
<insert id="insertProduct" parameterType="com.pibigstar.model.User" >
<selectKey resultType="java.lang.Long" order="AFTER" keyProperty="id">
SELECT LAST_INSERT_ID()
</selectKey>
insert into user(userName,password,comment)
values(#{userName},#{password},#{comment})
</insert>
order为AFTER表示插入之后再进行查询一次
<selectKey resultType="java.lang.Long" order="AFTER" keyProperty="id">
SELECT LAST_INSERT_ID()
</selectKey>

本文详细介绍了MyBatis框架中的高级技巧,包括参数传递方式、驼峰命名规范配置、扫描包路径设置、联表查询、事务管理及主键返回等核心功能,并提供了具体的代码示例。
2581

被折叠的 条评论
为什么被折叠?



