1.复习
创建事务切面,辅助dao层的curd操作。要求:
1.把dao层,打开连接,开启事务,回滚事务,提交连接,关闭连接统一提取到事务切面
2.service层统一进行事务控制
事务切面应织入service层,dao层的方法是一个个独立的sql操作,而一个service可执行多次dao操作,希望多次dao操作在一个事务里。
新建项目,拷贝day05用到过的jar包和配置文件:
spring配置文件,留下ioc,aop注解识别
<?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" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <context:component-scan base-package="com.javasm"></context:component-scan> <import resource="dao.xml"></import> <aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy> </beans>
新建src.com.javasm.sys.entity.Sysuser:
public class Sysuser { private Integer id; private String uphone; private String uname; //setget }
src.com.javasm.sys.dao.IUserDao
//先使用原生jdbc,不用mybatis public interface IUserDao { int insertUser(Sysuser u) throws SQLException; int updateUser(Sysuser u) throws SQLException; Sysuser getById(Integer id) throws SQLException; }
dao.impl.UserDaoImpl
@Repository public class UserDaoImpl implements IUserDao { //dao层依赖于Datesources @Autowired private DataSource ds; @Override public int insertUser(Sysuser u) throws SQLException { String sql = " insert into sys_user(uname,uphone) values (?,?) "; Connection connection = ds.getConnection(); PreparedStatement pst = connection.prepareStatement(sql); pst.setString(1,u.getUname()); pst.setString(2,u.getUphone()); int i = pst.executeUpdate(); connection.close(); return i; } @Override public int updateUser(Sysuser u) throws SQLException { String sql = " update sys_user set uname=?,uphone=? where id=? "; Connection connection = ds.getConnection(); PreparedStatement pst = connection.prepareStatement(sql); pst.setString(1,u.getUname()); pst.setString(2,u.getUphone()); pst.setInt(3,u.getId()); int i = pst.executeUpdate(); //executeUpdate方法会自动提交 connection.close(); return i; } @Override public Sysuser getById(Integer id) throws SQLException { String sql = " select id,uname,uohone from sys_user where id=? "; Connection connection = ds.getConnection(); PreparedStatement pst = connection.prepareStatement(sql); pst.setInt(1,id); ResultSet resultSet = pst.executeQuery(); boolean next = resultSet.next(); if(!next) return null; String uname = resultSet.getString("uname"); String uphone = resultSet.getString("uphone"); Sysuser u = new Sysuser(); u.setId(id); u.setUname(uname); u.setUphone(uphone); connection.close(); return u; } }
测试,新建test.com.javasm.TestDao
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:spring.xml") public class TestDao { @Resource private IUserDao ud; @Test public void dao_insert() throws SQLException { Sysuser u = new Sysuser(); u.setUname("bbb"); u.setUphone("123123"); ud.insertUser(u); } @Test public void dao_update() throws SQLException { Sysuser u = new Sysuser(); u.setId(8); u.setUname("bbb2"); u.setUphone("1111111"); ud.updateUser(u); } }
数据库插入,更新成功
新建src.com.javasm.sys.service.IUserService
public interface IUserService { Sysuser getById(Integer id) throws SQLException; int insert(Sysuser u) throws SQLException; int update(Sysuser u) throws SQLException; //u1插入数据库,u2更新一下 boolean insertAndUpdate(Sysuser u1,Sysuser u2) throws SQLException; }
新建service.impl.UserServiceImpl
@Service public class UserServiceImpl implements IUserService { //service依赖于dao @Autowired private IUserDao ud; @Override public int insert(Sysuser u) throws SQLException { return ud.insertUser(u); } @Override public int update(Sysuser u) throws SQLException { return ud.updateUser(u); } @Override public boolean insertAndUpdate(Sysuser u1, Sysuser u2) throws SQLException { //要求插入和更新在同一个事务,要么都成功,要么都失败。那需要插入更新需要同一个连接 ud.insertUser(u1); ud.updateUser(u2); return true; } @Override public Sysuser getById(Integer id) throws SQLException { return ud.getById(id); } }
测试insertAndUpdate方法,com.javasm.TestService
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:spring.xml") public class TestService { @Resource private IUserService us; @Test public void Service_insertAndUpdate() throws SQLException { Sysuser u = new Sysuser(); u.setUname("bbb3"); u.setUphone("123123"); Sysuser u1 = new Sysuser(); u1.setId(8); u1.setUname("ccc"); u1.setUphone("ccc11111"); us.insertAndUpdate(u,u1); } }
显然此时insertAndUpdate方法的插入和更新不再同一个事务,两者没有关系,各走各的。
1.aop之事务切面
事务管理器对象依赖DataSource连接池,提供打开连接,开启事务,提交事务,回滚,关闭等操作方法;
事务切面依赖事务管理器对象,对带有Tx注解的服务层方法进行环绕通知注入,进行统一事务控制;
通过ThreadLocal线程变量对象来达到线程共享Connection对象的目的.
新建src.com.javasm.aspects.TransactionAspect
@Component @Aspect public class TransactionAspect { @Pointcut("execution(* com.javasm.*.service.impl.*.*(..))") public void txpc(){} @Around("txpc()") public Object doTx(ProceedingJoinPoint jp){ Object result = null; try { //打开连接 Object proceed = jp.proceed(); //提交 } catch (Throwable throwable) { //回滚 }finally { //关闭 } return result; } }
实际上,service层并不是所有方法都做dao层操作,故用注解的写法:
新建aspects.Tx
@Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Tx { }
在TransactionAspect
@Pointcut("@annotation(com.javasm.aspects.Tx)") public void txpc(){}
在UserServiceImpl中,insertAndUpdate方法上加@Tx,只在该方法开事务。
新建aspects.CurrentConnection
@Component public class CurrentConnection { //不能为static变量注入值 private static DataSource ds; //静态变量是全局共享的,跨线程共享的 //需要让这个变量称为一个之间隔离的变量,只有同一个线程内部才共享这个变量 private static ThreadLocal<Connection> threadLocalConn=new ThreadLocal<>(); @Resource public void setDs(DataSource dataSource){ ds=dataSource; } public static Connection getCurrentOpenConn(){ Connection connection = threadLocalConn.get(); return connection; } public static Connection getConn() { Connection connection = threadLocalConn.get(); if(connection==null){ //connectin为null,说明当前dao方法所在线程,未被事务切面织入,临时打开一个连接 try { connection = ds.getConnection(); threadLocalConn.set(connection); } catch (SQLException throwables) { throwables.printStackTrace(); } } return connection; } public static void setConn(Connection conn) { threadLocalConn.set(conn); } public static void removeConn(){ threadLocalConn.remove(); } }
aspects.TransactionAspect
@Component @Aspect public class TransactionAspect { @Autowired private DataSource ds; @Pointcut("@annotation(com.javasm.aspects.Tx)") public void txpc(){} @Around("txpc()") public Object doTx(ProceedingJoinPoint jp){ Object proceed = null; try { //打开连接 //线程变量对象ThreadLocal,此对象作用:达到同一个线程中共享变量 //注:static修饰的静态变量是全局共享,跨线程共享。 Connection connection = ds.getConnection(); proceed = jp.proceed(); //提交 } catch (Throwable throwable) { //回滚 }finally { return proceed; } } }
aspects.CloseConnectinAspect
@Component @Aspect public class CloseConnectinAspect { @Autowired private MyTransactionManager tm; @Pointcut("execution(* com.javasm.*.service.impl.*.*(..))") public void servicepc(){} @After("servicepc()") public void close(){ tm.close(); } }
TransactionAspect中:
@Component @Aspect public class TransactionAspect { @Autowired private MyTransactionManager tm; @Pointcut("@annotation(com.javasm.aspects.Tx)") public void txpc(){} @Around("txpc()") public Object doTx(ProceedingJoinPoint jp){ Object result =null; try { tm.openConnection(); tm.beginTransaction(); result = jp.proceed(); tm.commit(); } catch (Throwable throwable) { tm.rollback(); }finally { return result; } } }
IUserDao:
public interface IUserDao { int insertUser(Sysuser u) throws SQLException; int updateUser(Sysuser u) throws SQLException; Sysuser getById(Integer id) throws SQLException; }
UserDaoImpl:
@Repository public class UserDaoImpl implements IUserDao { @Override public int insertUser(Sysuser u) throws SQLException { Connection connection = CurrentConnection.getConn(); String sql = "insert into sys_user(uname,uphone) values(?,?)"; PreparedStatement pst = connection.prepareStatement(sql); pst.setString(1,u.getUname()); pst.setString(2,u.getUphone()); int i = pst.executeUpdate(); return i; } @Override public int updateUser(Sysuser u) throws SQLException { Connection connection = CurrentConnection.getConn();//如果线程变量中有Connection,则获取;如果没有则临时打开Connection并加入线程变量 String sql = "update sys_user set uname=?,uphone=? where id=?"; PreparedStatement pst = connection.prepareStatement(sql); pst.setString(1,u.getUname()); pst.setString(2,u.getUphone()); pst.setInt(3,u.getId()); int i = pst.executeUpdate(); return i; } @Override public Sysuser getById(Integer id) throws SQLException { Connection connection = CurrentConnection.getConn(); String sql = "select id,uname,uphone from sys_user where id=?"; PreparedStatement pst = connection.prepareStatement(sql); pst.setInt(1,id); ResultSet resultSet = pst.executeQuery(); boolean next = resultSet.next(); if(!next)return null; String uname = resultSet.getString("uname"); String uphone = resultSet.getString("uphone"); Sysuser u =new Sysuser(); u.setId(id); u.setUname(uname); u.setUphone(uphone); return u; } }
IUserService:
public interface IUserService { String add(int a,int b); Sysuser getById(Integer id) throws SQLException; int insert(Sysuser u) throws SQLException; int update(Sysuser u) throws SQLException; boolean insertAndUpdate(Sysuser u1,Sysuser u2) throws SQLException; }
UserServiceImpl:
@Service public class UserServiceImpl implements IUserService { @Autowired private IUserDao ud; @Override public String add(int a, int b) { return String.valueOf(a+b); } @Override public Sysuser getById(Integer id) throws SQLException { return ud.getById(id); } @Override public int insert(Sysuser u) throws SQLException { return ud.insertUser(u); } @Override public int update(Sysuser u) throws SQLException { return ud.updateUser(u); } @Tx @Override public boolean insertAndUpdate(Sysuser u1, Sysuser u2) throws SQLException { ud.insertUser(u1); ud.updateUser(u2); return true; } }
2.spring的类配置
spring容器ApplicationContext的创建,可以使用ClasspathXMLApplicationContext对象来加载类路劲下的xml配置文件;学习ssm框架使用.
spring容器ApplicationContext的创建,,可以使用AnnationConfigApplicationContext对象来加载类配置文件.springboot框架使用.
只要是xml里可配置的东西,类里都可配置
看下xml的配置
dao.xml
<?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 https://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder location="jdbc.properties"></context:property-placeholder> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="driverClassName" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> <property name="initialSize" value="${jdbc.initSize}"></property> <property name="maxActive" value="${jdbc.maxActive}"></property> </bean> </beans>
spring.xml
<?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" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <context:component-scan base-package="com.javasm"></context:component-scan> <import resource="dao.xml"></import> <aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy> </beans>
jdbc.properties
jdbc.url=jdbc:mysql://127.0.0.1:3306/704A?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC jdbc.driver=com.mysql.jdbc.Driver jdbc.username=root jdbc.password=root jdbc.initSize=4 jdbc.maxActive=10
用类配置方法去写:
新建src.com.javasm.config.DaoConfig
@Configuration //定义配置类 @PropertySource("classpath:jdbc.properties") //导入properties文件 //@PropertySources() 加载多个文件 public class DaoConfig { @Value("${jdbc.driver}") //获取key为jdbc.dirver的值 private String driverClassName; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Value("${jdbc.initSize}") private Integer initSize; @Value("${jdbc.maxActive}") private Integer maxActive; //把方法的返回值注册spring容器,方法名作为默认id,方法形参进行依赖注入 //不想用方法名作为id,也可用value自己起名 @Bean(initMethod = "init",destroyMethod = "close",value = "dataSource") public DruidDataSource createDataSource(){ DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setUrl(url); druidDataSource.setDriverClassName(driverClassName); druidDataSource.setUsername(username); druidDataSource.setPassword(password); druidDataSource.setInitialSize(initSize); druidDataSource.setMaxActive(maxActive); return druidDataSource; } }
config.AppConfig
@Configuration //表示当前类是一个spring风格的配置类,等价于xml文件 @Import(DaoConfig.class) //导入其他类配置文件 @ComponentScan("com.javasm") //开启包扫描 @EnableAspectJAutoProxy //开启aop注解识别 public class AppConfig { //主配置 }
新建TestClzConfig
public class TestClzConfig { @Test public void initApplicationContext(){ //解析配置类中的成员变量和方法上的注解,进行IOC与DI //并把配置类也注册到sprign容器 ApplicationContext c = new AnnotationConfigApplicationContext(AppConfig.class); IUserService bean = c.getBean(IUserService.class); } }
3.mybatis复习
3.1 创建如下表:
字典表
sys_dict_type:字典类型表
sys_dict_items:字典项表
部门表
岗位表
菜单表
角色表,与菜单表多对多
用户表,与角色表多对一,与部门表多对一,与岗位表多对一
3.2 安装easycode插件进行代码生成
(可以多张表一起选)
写包名,即生成到哪个包,路径会根据包名自动补全
选择要生成的内容
可修改类型映射,如时间戳对应java.lang.String
dao接口基本方法有增删改查,还想要批量删,批量查
进行模板设置
模板如下:
Entity
##引入宏定义 $!define ##使用宏定义设置回调(保存位置与文件后缀) #save("/entity", ".java") ##使用宏定义设置包后缀 #setPackageSuffix("entity") ##使用全局变量实现默认包导入 $!autoImport import java.io.Serializable; ##使用宏定义实现类注释信息 #tableComment("实体类") public class $!{tableInfo.name} implements Serializable { private static final long serialVersionUID = $!tool.serial(); #foreach($column in $tableInfo.fullColumn) #if(${column.comment})/** * ${column.comment} */#end private $!{tool.getClsNameByFullName($column.type)} $!{column.name}; #end #foreach($column in $tableInfo.fullColumn) ##使用宏定义实现get,set方法 #getSetMethod($column) #end }
Dao
##定义初始变量 #set($tableName = $tool.append($tableInfo.name, "Dao")) ##设置回调 $!callback.setFileName($tool.append($tableName, ".java")) $!callback.setSavePath($tool.append($tableInfo.savePath, "/dao")) ##拿到主键 #if(!$tableInfo.pkColumn.isEmpty()) #set($pk = $tableInfo.pkColumn.get(0)) #end #if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}dao; import $!{tableInfo.savePackageName}.entity.$!{tableInfo.name}; import com.javasm.commons.basic.BaseDao; public interface $!{tableName} extends BaseDao<$!{tableInfo.name}>{ }
Service
##定义初始变量 #set($tableName = $tool.append($tableInfo.name, "Service")) ##设置回调 $!callback.setFileName($tool.append($tableName, ".java")) $!callback.setSavePath($tool.append($tableInfo.savePath, "/service")) ##拿到主键 #if(!$tableInfo.pkColumn.isEmpty()) #set($pk = $tableInfo.pkColumn.get(0)) #end #if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}service; import com.javasm.commons.basic.BaseService; import $!{tableInfo.savePackageName}.entity.$!{tableInfo.name}; import java.util.List; public interface $!{tableName} extends BaseService<$!{tableInfo.name}> { }
serviceImpl
##定义初始变量 #set($tableName = $tool.append($tableInfo.name, "ServiceImpl")) ##设置回调 $!callback.setFileName($tool.append($tableName, ".java")) $!callback.setSavePath($tool.append($tableInfo.savePath, "/service/impl")) ##拿到主键 #if(!$tableInfo.pkColumn.isEmpty()) #set($pk = $tableInfo.pkColumn.get(0)) #end #if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}service.impl; import $!{tableInfo.savePackageName}.entity.$!{tableInfo.name}; import $!{tableInfo.savePackageName}.dao.$!{tableInfo.name}Dao; import $!{tableInfo.savePackageName}.service.$!{tableInfo.name}Service; import org.springframework.stereotype.Service; import com.javasm.commons.basic.BaseServiceImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Service public class $!{tableName} extends BaseServiceImpl<$!{tableInfo.name}Dao,$!{tableInfo.name}> implements $!{tableInfo.name}Service { private static Logger l = LoggerFactory.getLogger($!{tableName}.class); }
Controller
##定义初始变量 #set($tableName = $tool.append($tableInfo.name, "Controller")) ##设置回调 $!callback.setFileName($tool.append($tableName, ".java")) $!callback.setSavePath($tool.append($tableInfo.savePath, "/controller")) ##拿到主键 #if(!$tableInfo.pkColumn.isEmpty()) #set($pk = $tableInfo.pkColumn.get(0)) #end #if($tableInfo.savePackageName)package $!{tableInfo.savePackageName}.#{end}controller; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.javasm.commons.basic.BaseController; import com.javasm.commons.entity.AxiosResult; import com.javasm.commons.entity.TableDatas; import $!{tableInfo.savePackageName}.entity.$!{tableInfo.name}; import $!{tableInfo.savePackageName}.service.$!{tableInfo.name}Service; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.Arrays; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @RestController @RequestMapping("$!tool.firstLowerCase($tableInfo.name)") public class $!{tableName} extends BaseController { private static Logger l = LoggerFactory.getLogger($!{tableName}.class); @Resource private $!{tableInfo.name}Service $!tool.firstLowerCase($tableInfo.name)Service; @GetMapping("{id}") public AxiosResult selectById(@PathVariable $!pk.shortType id) { $!{tableInfo.name} obj = this.$!{tool.firstLowerCase($tableInfo.name)}Service.queryById(id); return suc(obj); } @GetMapping("ids/{ids}") public AxiosResult selectListByIds(@PathVariable String ids) { String[] idsArray = ids.split(","); List<$!{tableInfo.name}> list = this.$!{tool.firstLowerCase($tableInfo.name)}Service.queryByIds(Arrays.asList(idsArray)); return suc(list); } @GetMapping("list") public TableDatas selectList($!{tableInfo.name} obj) { startPage(); List<$!{tableInfo.name}> list = this.$!{tool.firstLowerCase($tableInfo.name)}Service.queryList(obj); return toTableDatas(list); } @PostMapping public AxiosResult add(@RequestBody $!{tableInfo.name} obj) { Boolean r = this.$!{tool.firstLowerCase($tableInfo.name)}Service.insert(obj); return isok(r); } @PutMapping public AxiosResult update(@RequestBody $!{tableInfo.name} obj) { Boolean r = this.$!{tool.firstLowerCase($tableInfo.name)}Service.update(obj); return isok(r); } @DeleteMapping("{ids}") public AxiosResult delByIds(@PathVariable String ids) { String[] idsArray = ids.split(","); Boolean r = this.$!{tool.firstLowerCase($tableInfo.name)}Service.deleteByIds(Arrays.asList(idsArray)); return isok(r); } }
Mapper
##引入mybatis支持 $!mybatisSupport ##设置保存名称与保存位置 $!callback.setFileName($tool.append($!{tableInfo.name}, "Dao.xml")) $!callback.setSavePath($tool.append($modulePath, "/src/main/resources/mapper")) ##拿到主键 #if(!$tableInfo.pkColumn.isEmpty()) #set($pk = $tableInfo.pkColumn.get(0)) #end <?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="$!{tableInfo.savePackageName}.dao.$!{tableInfo.name}Dao"> <resultMap type="$!{tableInfo.savePackageName}.entity.$!{tableInfo.name}" id="$!{tableInfo.name}Map"> #foreach($column in $tableInfo.fullColumn) <result property="$!column.name" column="$!column.obj.name"/> #end </resultMap> <sql id="basicQuery"> select #allSqlColumn() from $!{tableInfo.obj.parent.name}.$!tableInfo.obj.name </sql> <select id="queryById" resultMap="$!{tableInfo.name}Map"> <include refid="basicQuery"></include> where $!pk.obj.name = #{$!pk.name} </select> <select id="queryByIds" resultMap="$!{tableInfo.name}Map"> <include refid="basicQuery"></include> where $!pk.obj.name in <foreach collection="list" open="(" close=")" item="i" separator=","> #{i} </foreach> </select> <select id="queryAll" resultMap="$!{tableInfo.name}Map"> <include refid="basicQuery"></include> <where> #foreach($column in $tableInfo.fullColumn) <if test="$!column.name != null#if($column.type.equals("java.lang.String")) and $!column.name != ''#end"> and $!column.obj.name = #{$!column.name} </if> #end </where> </select> <insert id="insert" keyProperty="$!pk.name" useGeneratedKeys="true"> insert into $!{tableInfo.obj.parent.name}.$!{tableInfo.obj.name}(#foreach($column in $tableInfo.otherColumn)$!column.obj.name#if($velocityHasNext), #end#end) values (#foreach($column in $tableInfo.otherColumn)#{$!{column.name}}#if($velocityHasNext), #end#end) </insert> <update id="update"> update $!{tableInfo.obj.parent.name}.$!{tableInfo.obj.name} <set> #foreach($column in $tableInfo.otherColumn) <if test="$!column.name != null#if($column.type.equals("java.lang.String")) and $!column.name != ''#end"> $!column.obj.name = #{$!column.name}, </if> #end </set> where $!pk.obj.name = #{$!pk.name} </update> <delete id="deleteById"> delete from $!{tableInfo.obj.parent.name}.$!{tableInfo.obj.name} where $!pk.obj.name = #{$!pk.name} </delete> <delete id="deleteByIds"> delete from $!{tableInfo.obj.parent.name}.$!{tableInfo.obj.name} where $!pk.obj.name in <foreach collection="list" open="(" close=")" item="i" separator=","> #{i} </foreach> </delete> </mapper>