- mybtis中的级联关系(关联关系、集合关系)association、collection(一对一关系、一对多关系、多对多关系):https://blog.csdn.net/IT_CREATE/article/details/86523101
- mybatis框架之mapper的xml映射配置的编写(insert、delete、update、select标签使用):https://blog.csdn.net/IT_CREATE/article/details/85687293
- mybatis中动态sql的操作(where、foreach、if、set、choose、trim标签的使用):https://blog.csdn.net/IT_CREATE/article/details/86557260
- mybatis中的级联关系中的鉴别器(discriminator、case、result):https://blog.csdn.net/IT_CREATE/article/details/86561051
编写applicationContext.xml完成框架的整合(maven创建项目)
第1步:开启spring容器的自动扫描功能
第2步:引入外部的数据库配置描述文件
第3步:配置数据源连接池:C3P0,DBCP2,DRUID
第4步:配置SessionFactory
第5步:配置MapperScanner
第6步:配置事务管理器
第7步:配置spring管理事务的2种方式:编程式事务管理,声明式事务管理(一般用声明式)
第8步:开启切面动态代理支持
需要jar包(必须):aspectjrt、aspectjweaver、commons-dbcp2、mybatis-spring、mybatis、mysql-connector-java、spring-context、spring-jdbc
测试jar包(可选):spring-test、junit
日志jar包(可选):log4j
mysql.properties文件:(连接数据库要要用到的信息)
jdbc.driver=org.gjt.mm.mysql.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF8&allowMultiQueries=true
jdbc.username=root
jdbc.password=1234
这里配置有个注意的地方:
有个常见的场景:删除用户的时候需要先删除用户的外键关联数据,否则会触发规则报错。
解决办法不外乎有三个:1、多条sql分批执行;2、存储过程或函数调用;3、sql批量执行。
今天我要说的是MyBatis中如何一次执行多条语句(使用mysql数据库)。
1、修改数据库连接参数加上allowMultiQueries=true,如:
jdbc.url=jdbc:mysql://xx.xx.xx:3306/xxxxx?characterEncoding=utf-8&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true
2、直接写多条语句,用“;”隔开即可
<delete id="deleteUserById" parameterType="long">
delete from sec_user_role where userId=#{id};
delete from sec_user where id=#{id};
</delete>
applicationContext.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 第1步:开启spring容器的自动扫描功能 -->
<context:component-scan base-package="com.ali.sm"></context:component-scan>
<!-- 第2步:引入外部的数据库配置描述文件 -->
<context:property-placeholder location="classpath:mysql.properties" />
<!-- 第3步:配置数据源连接池:C3P0,DBCP2,DRUID -->
<!-- destroy-method="close" 该方法代表spring容器在销毁时,需要调用close(),关闭掉所有的数据库连接对象 -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<!-- 配置4个最基本的连接属性 -->
<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="defaultAutoCommit" value="false"></property>
<property name="defaultReadOnly" value="false"></property>
<!-- 在数据库中,隔离级别:8代表可串行化,4代表可重复读,2代表读已提交 ,1代表读未提交 -->
<property name="defaultTransactionIsolation" value="4"></property>
<!-- 创建连接池时,需要初始化的连接数量 -->
<property name="initialSize" value="15"></property>
<!-- 配置连接池中,最大能存放的连接数量 -->
<property name="maxTotal" value="50"></property>
<!-- 配置连接池中,允许存在的最大空闲状态的连接数量 -->
<property name="maxIdle" value="35"></property>
<property name="minIdle" value="0"></property>
<!-- 设置连接池中,连接处理SQL语句的超时时间,不可能无限制的等 -->
<property name="defaultQueryTimeout" value="5"></property>
<!-- 设置数据库查询校验语句 -->
<property name="validationQuery" value="select now() from dual"></property>
<!-- 设置当连接在创建时,或者是在借出时,都需要执行SQL验证,用于确保连接是可用的 -->
<property name="testOnCreate" value="true"></property>
<property name="testOnBorrow" value="true"></property>
<!-- 设置数据查询校验失败超时时间 -->
<property name="validationQueryTimeout" value="5"></property>
<!-- 代表连接池允许存放,SQL预编译对象 -->
<property name="poolPreparedStatements" value="true"></property>
<!-- 允许存放120个预编译对象 -->
<property name="maxOpenPreparedStatements" value="120"></property>
</bean>
<!-- 第4步,配置SessionFactory -->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<!-- typeAliasesPackage 以包为单位,批量给包中的类取类别名 如果存在多个包同时需要取类别名,包和包之间,采用;或者,间隔 -->
<property name="typeAliasesPackage" value="com.ali.sm.bean"></property>
</bean>
<!-- 第5步,配置MapperScanner -->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- basePackage 以包为单位,批量扫描包中的映射关系 如果存在多个包同时需要扫描,包和包之间,采用;或者,间隔 -->
<property name="basePackage" value="com.ali.sm.usermag.mapper;
com.ali.sm.logmag.mapper"></property>
<property name="sqlSessionFactoryBeanName" value="sessionFactory"></property>
</bean>
<!-- 第6步,配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 第7步,配置spring管理事务。它的2种方式:编程式事务管理,声明式事务管理 -->
<!-- 编程式事务管理 需要在业务类中,借助TransactionTemplate,PlatformTransactionManager 完成对业务逻辑
的逻辑事务管理,不推荐使用 -->
<!-- 声明式事务管理,第1种方式,采用AOP管理业务逻辑事务 -->
<!-- <tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" read-only="true" propagation="SUPPORTS" />
<tx:method name="save*" read-only="false" rollback-for="java.lang.Exception"
propagation="REQUIRED" />
<tx:method name="add*" read-only="false" rollback-for="java.lang.Exception"
propagation="REQUIRED" />
<tx:method name="insert*" read-only="false" rollback-for="java.lang.Exception"
propagation="REQUIRED" />
<tx:method name="create*" read-only="false" rollback-for="java.lang.Exception"
propagation="REQUIRED" />
<tx:method name="update*" read-only="false" rollback-for="java.lang.Exception"
propagation="REQUIRED" />
<tx:method name="modify*" read-only="false" rollback-for="java.lang.Exception"
propagation="REQUIRED" />
<tx:method name="change*" read-only="false" rollback-for="java.lang.Exception"
propagation="REQUIRED" />
<tx:method name="delete*" read-only="false" rollback-for="java.lang.Exception"
propagation="REQUIRED" />
<tx:method name="remove*" read-only="false" rollback-for="java.lang.Exception"
propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txMagPoint"
expression="execution(* com.ali.sm.*mag.service.impl.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="txMagPoint" />
</aop:config> -->
<!-- 声明式事务管理,第2种方式,使用@Transactional管理业务逻辑事务 -->
<!-- 开启事务的注解支持 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 第8步,开启切面动态代理支持 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
第一种声明式方式中,<tx:method/>标签的name属性,表示切入哪些方法,上面的写法中 name="add*"这种方式写法,表示凡是以这个开头的方法都被切入事务。其余参数意思跟下面要介绍的注解的参数意思一致,看下面。
我更倾向于使用第一种声明式方式,如果用了第二种声明式@Transactional的方式,那么需要在业务层的方法上加上@Transactional注解,如下(我这里用了第二种):
/**
* @Service 表示该Java类是一个需要被spring容器管理起来的业务层的组件
* 默认情况下,spring容器扫描到该组件之后,将会将该类的类名 “首字母小写后的字符串”,作为该组件在容器中的ID
* 当然你也可以通过@Service("sb")这种方式去改
* @author Administrator
*
*/
@Transactional(readOnly=true,propagation=Propagation.SUPPORTS)
@Service
public class UserServiceImpl implements IUserService {
/**
* @Resource 约== @Autowired + @Qualifier
* 默认情况下,@Resource将先按照byName装配方式进行精准装配,如果装配失败,将回退到byType装配方式
*
* 如果你指定了name="userDaoImpl3" ,那么将严格按照byName的装配方式,不会回退
*/
@Resource
private IUserDao userDaoImpl;
@Transactional(readOnly=false,propagation=Propagation.REQUIRED,rollbackFor=Exception.class)
@MyLog(value="用户管理",type=LogEnum.ADD)
@Override
public UserBean saveUserBean(UserBean user) {
// TODO Auto-generated method stub
userDaoImpl.addUserBean(user);
return user;
}
@Transactional(readOnly=false,propagation=Propagation.REQUIRED,rollbackFor=Exception.class)
@MyLog(value="用户管理",type=LogEnum.ADD)
@Override
public int addBatchUserBean(List<UserBean> users) {
// TODO Auto-generated method stub
return userDaoImpl.addBatchUserBean(users);
}
@Transactional(readOnly=false,propagation=Propagation.REQUIRED,rollbackFor=Exception.class)
@MyLog(value="用户管理",type=LogEnum.UPDATE)
@Override
public int updateUserBean(UserBean user) {
// TODO Auto-generated method stub
return userDaoImpl.updateUserBean(user);
}
@Transactional(readOnly=false,propagation=Propagation.REQUIRED,rollbackFor=Exception.class)
@MyLog(value="用户管理",type=LogEnum.DELETE)
@Override
public int deleteUserBean(UserBean user) {
// TODO Auto-generated method stub
return userDaoImpl.deleteUserBean(user);
}
@Transactional(readOnly=false,propagation=Propagation.REQUIRED,rollbackFor=Exception.class)
@MyLog(value="用户管理",type=LogEnum.DELETE)
@Override
public int deleteBatchUserBean(int[] ids) {
// TODO Auto-generated method stub
return userDaoImpl.deleteBatchUserBean(ids);
}
@Transactional(readOnly=false,propagation=Propagation.REQUIRED,rollbackFor=Exception.class)
@MyLog(value="用户管理",type=LogEnum.DELETE)
@Override
public int deleteUserBean(Integer id) {
// TODO Auto-generated method stub
return userDaoImpl.deleteUserBean(id);
}
@Override
public UserBean getUserBeanById(Integer id) {
// TODO Auto-generated method stub
return userDaoImpl.getUserBeanById(id);
}
@Override
public Map<String, Object> queryUserBeanById(Integer id) {
// TODO Auto-generated method stub
return userDaoImpl.queryUserBeanById(id);
}
@Override
public List<Map<String, Object>> findUserBeanMapByObject(UserBean user) {
// TODO Auto-generated method stub
return userDaoImpl.findUserBeanMapByObject(user);
}
@Override
public UserBean findUserBeanByLoginNameAndPwd(String loginName, String pwd) {
// TODO Auto-generated method stub
return userDaoImpl.findUserBeanByLoginNameAndPwd(loginName, pwd);
}
@Override
public List<UserBean> findUserBeanByObject(UserBean user) {
// TODO Auto-generated method stub
return userDaoImpl.findUserBeanByObject(user);
}
@Override
public List<UserBean> findUserBeanByMap(Map map) {
// TODO Auto-generated method stub
return userDaoImpl.findUserBeanByMap(map);
}
@Override
public PageBean findUserBeanList2PageBean(PageBean page, UserBean user) {
// TODO Auto-generated method stub
int totalRows = userDaoImpl.countUserBeanList2PageBean(user);
List<?> datas = null;
if(totalRows > 0) {
datas = userDaoImpl.findUserBeanList(page, user);
}
page.setTotalRows(totalRows);
page.setData(datas);
return page;
}
}
@Transactional(readOnly=false,propagation=Propagation.REQUIRED,rollbackFor=Exception.class) 这个注解的几个属性含义:
readOnly:表示是否操作的数据库时是否只读
propagation:表示这些方法如何使用这些事务,有七种方式:
REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
rollbackFor:表示在什么时候进行回滚,这里是发生异常回滚
要做事务提交和回滚的只有增删改操作,所以查询我们就不用去加这个注解,那个@Mylog注解不用管,这个是我自己写的,主要是用AOP来做操作日志记录的,跟本次配置无关。
MyLog注解:
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.gezhi.sm.enumration.LogEnum;
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
/**
* value 代表着 具体的操作模块
* @return
*/
String value() default "";
/**
* 操作类型 0- 新增,1-修改,2-删除
* @return
*/
LogEnum type();
}
maven的pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ali</groupId>
<artifactId>sm</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>sm</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<spring.version>4.3.14.RELEASE</spring.version>
<aspect.version>1.8.9</aspect.version>
<mybatis.version>3.3.0</mybatis.version>
<mysql.version>5.1.38</mysql.version>
<dbcp.version>2.4.0</dbcp.version>
</properties>
<dependencies>
<!-- 引入第3方的切面框架AspectJrt的相关JAR文件 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspect.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspect.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>${dbcp.version}</version>
</dependency>
<!-- 导入mybatis 兼容spring框架的JAR包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!-- 引入mybatis 相关jar包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- 导入spring容器相关JAR文件 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- 引入spring框架兼容Junit单元测试框架的相关JAR包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<!-- 导入junit单元测试框架JAR包 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- 导入LOG4J日志框架JAR包 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<!-- 配置maven 在构建项目时,采用相关插件 -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>