Spring概述
初次使用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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.chapter01.User"></bean>
public void test(){
//加载spring文件 ApplicationContext:应用上下文 ClassPathXmlApplicationContext:上下文xml类路径(xml的名称,xml里面包含了路径) 获取IOC容器
ApplicationContext context = new ClassPathXmlApplicationContext("test1.xml");
//获取配置创建对象
User user = context.getBean("user", User.class);//获取User的class类,把接收到的object转化为User类
System.out.println(user);
user.add();
IOC容器(控制翻转)
创建对象的过程交给spring来管理,对象创建控制权由程序交给外部来处理。这种思想称为控制反转。IOC就是用于充当思想中的外部
原理
接口(beanFactory接口)
创建IOC容器
获取容器内的bean
引入外部属性文件
2.把外部properties文件引入到spring配置文件中(需要引入context名称空间)
<?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:util="http://www.springframework.org/schema/util"
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/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--引入外部标签上下文-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driverClassName}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
</bean>
DI(依赖注入)(基于XML)
在IOC容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入(DI)。一个对象里面有个属性是其他对象,就需要把其他对象的bean注入到该对象的属性中(原始方法是在该对象内new一个其他对象,但是这样耦合度太高了)
内部属性(内部标签)
使用 set 方法进行注入(property标签)
(1)创建类,定义属性和对应的 set 方法
/**
* 演示使用 set 方法进行注入属性
*/
public class Book {
//创建属性
private String bname;
private String bauthor;
//创建属性对应的 set 方法
public void setBname(String bname) {
this.bname = bname;
}
public void setBauthor(String bauthor) {
this.bauthor = bauthor;
}
}
(2)在 spring 配置文件配置对象创建,配置属性注入
<!--2 set 方法注入属性-->
<bean id="book" class="com.atguigu.spring5.Book">
<!--使用 property 完成属性注入
name:类里面属性名称
value:向属性注入的值
-->
<property name="bname" value="易筋经"></property>
<property name="bauthor" value="达摩老祖"></property>
使用有参数构造进行注入(constructor-arg标签)
(1)创建类,定义属性,创建属性对应有参数构造方法
package com.chapter01;
public class User {
String name;
public void setName(String name) {
this.name = name;
}
public void add(){
System.out.println(name);
}
public User(String name) {
this.name = name;
}
}
(2)在 spring 配置文件中进行配置
<!--3 有参数构造注入属性-->
<bean id="user" class="com.chapter01.User">
<constructor-arg name="name" value="kevin"></constructor-arg>
p名称空间注入
直接在标签里面注入值,省去了创建子节点标签,如constructor-arg标签和property标签
其他符号属性
内部bean
<bean id="user" class="com.chapter01.User">
<property name="name" value="kevin"></property>
<!--内部bean要写到属性里面(用属性框包起来)-->
<property name="dept" >
<bean id="dept" class="com.chapter01.Dept">
<property name="name" value="学生会"></property>
</bean>
</property>
外部bean(级联的一种)
<bean id="user" class="com.chapter01.User">
<property name="name" value="kevin"></property>
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.chapter01.Dept">
<property name="name" value="学生"></property>
级联操作
<bean id="user" class="com.chapter01.User">
<property name="name" value="kevin"></property>
<!--级联赋值-->
<property name="dept" ref="dept"></property>
<!--直接设置值,需要有get方法-->
<property name="dept.name" value="校董会"></property>
</bean>
集合注入
<bean id="ALS" class="com.chapter01.Arr_List_Set">
<!--数组元素注入-->
<property name="arr">
<array>
<value>java</value>
<value>c++</value>
</array>
</property>
<!--List元素注入-->
<property name="list">
<list>
<value>虹猫</value>
<value>蓝兔</value>
</list>
</property>
<!--map元素注入-->
<property name="map">
<map>
<entry key="cctv6" value="电影"></entry>
<entry key="cctv10" value="科教"></entry>
</map>
</property>
<!--set元素注入-->
<property name="set">
<set>
<value>苹果</value>
<value>菠萝</value>
</set>
</property>
<!--对象注入-->
<property name="depts">
<list>
<ref bean="dept1"></ref>
<ref bean="dept2"></ref>
</list>
</property>
</bean>
<!--创建多个dept对象方便引入-->
<bean id="dept1" class="com.chapter01.Dept">
<property name="name" value="娃哈哈"></property>
</bean>
<bean id="dept2" class="com.chapter01.Dept">
<property name="name" value="吉哈哈"></property>
集合注入抽取
如果一个集合希望被其他bean调用的话,可以把集合提取出来(类似于提取为公共类)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<util:list id="bookList">
<value>三国演义</value>
<value>水浒传</value>
<value>红楼梦</value>
</util:list>
<bean id="book" class="com.chapter01.book">
<property name="names" ref="bookList"></property>
bean管理(xml)
概念
实现
(1)在 spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建
bean实例化方式
Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)
方式一 构造方法
在xml文件中通过类的构造方法来实例化其他bean类。(太繁琐)
方式二 工厂bean
创建一个实现了factoryBean接口的工厂类,用这个工厂类代理创建其他对象。然后再xml里面实例化这个工厂bean(所得到的bean是代理创建的对象,并不是这个工厂的bean)。(也实现了解耦)
bean的作用域(单双例)
默认单例
设置单实例还是多实例
spring 配置文件 bean 标签里面有属性(scope)用于设置单实例还是多实例
第一个值( 默认值),singleton,表示是单实例对象。
第一 singleton 单实例,prototype 多实例
第二 设置 scope 值是 singleton 时候,加载 spring 配置文件时候就会创建单实例对象 。设置 scope 值是 prototype 时候,不是在加载 spring 配置文件时候创建 对象,在调用getBean 方法时候创建多实例对象
bean的生命周期(带有后置处理器)
- (1)通过构造器创建 bean 实例(无参数构造)
- (2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
- (3)把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization (初始化前)
- (4)调用 bean 的初始化的方法(需要进行配置初始化的方法)
- (5)把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization(初始化后)
- (6)bean 可以使用了(对象获取到了)
- (7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
public Orders() {
System.out.println("第一步 执行无参数构造创建 bean 实例");
}
private String oname;
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步 调用 set 方法设置属性值");
}
//创建执行的初始化的方法
public void initMethod() {
System.out.println("第四步 执行初始化的方法");
}
//创建执行的销毁的方法
public void destroyMethod() {
System.out.println("第七步 执行销毁的方法");
}
//配置xml
<bean id="orders" class="com.atguigu.spring5.bean.Orders" initmethod="initMethod" destroy-method="destroyMethod">
<property name="oname" value="手机"></property>
</bean>
//设置后置处理器
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("第三步,在初始化之前执行的方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("第五步,在初始化之后执行的方法");
return bean;
}
}
<!--配置后置处理器xml-->
<bean id="myBeanPost" class="com.atguigu.spring5.bean.MyBeanPost"></bean>
//获取xml配置
@Test
public void testBean3() {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println("第六步 获取创建 bean 实例对象");
System.out.println(orders);
//手动让 bean 实例销毁
context.close();
xml的自动装配
bean将条件满足的外部bean自动引入。需要在bean标签里面申明两个属性
bean 标签属性 autowire,配置自动装配 autowire 属性常用两个值: byName 根据属性名称注入 ,注入值 bean 的 id 值和类属性名称一样 byType 根据属性类型注入
//根据属性名称引入
<bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byName">
<!--<property name="dept" ref="dept"></property>-->
</bean>
<bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
//根据类型引入,不能有多个相同属性
<bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byType">
<!--<property name="dept" ref="dept"></property>-->
</bean>
<bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
Bean管理(基于注解)
什么是注解
(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值..)
基于注解实现对象的创建
(1)@Component(2)@Service(3)@Controller(4)@Repository
* 上面四个注解功能是一样的,都可以用来创建 bean 实例
实现步骤
第一步:到spring文件包里引入aop.jar包(引入依赖)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
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/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--开启组件扫描 填入需要使用到注解的包-->
<context:component-scan base-package="com.chapter01"></context:component-scan>
@Component(value = "testBook")//给类起别名,默认是类名首字母小写 相当于xml<!-- id="testBook" ...
public class book {
private List<String> names;
public void show(){
System.out.println(names);
}
}
//调用
@Test
public void test(){
//加载spring文件 ApplicationContext:应用上下文 ClassPathXmlApplicationContext:上下文xml类路径(xml的名称,xml里面包含了路径)
ApplicationContext context = new ClassPathXmlApplicationContext("test1.xml");
//获取配置创建对象
book books = context.getBean("testBook", book.class);//获取User的class类,把接收到的object转化为User类
System.out.println(books);
books.show();
<!--示例 1 use-default-filters="false" 表示现在不使用默认 filter,自己配置 filter。 context:include-filter ,设置扫描哪些内容-->
<context:component-scan base-package="com.atguigu" use-defaultfilters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--示例 2下面配置扫描包所有内容
context:exclude-filter: 设置哪些内容不进行扫描-->
<context:component-scan base-package="com.atguigu">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
基于注解实现属性注入
@Qualifier:根据名称进行注入(@Qualifier 需要和上面@Autowired 一起使用)
//第一种 @Autowired:根据属性类型进行自动装配
@Component
public class Dept {
//定义 dao 类型属性 。不需要添加 set 方法 。添加注入属性注解
private String name;
@Autowired
private book book;
}
//第二种@Qualifier:根据名称进行注入(@Qualifier 需要和上面@Autowired 一起使用)
@Component
public class Dept {
private String name;
@Autowired
@Qualifier(value = "testBook")
private book book;
}
//第三种@Resource:可以根据类型注入,可以根据名称注入
@Component
public class Dept {
private String name;
@Resource(name = "testBook")
//不写值默认是根据类型注入,写了就是根据名字(id)进行注入
private book book;
}
//第四种@Value:注入普通类型属性
@Component
public class Dept {
@Value( value = "kevin")
private String name;
完全注解开发
@Configuration//标注为配置类
@ComponentScan(basePackages = {"com.chapter01"})//开启扫描(把扫描移到注解配置类里面)
public class SpringConfig {
@Test
public void test(){
//加载spring文件 ApplicationContext:应用上下文 AnnotationConfigApplicationContext:注解配置应用上下文xml类路径(xml的名称,xml里面包含了路径)
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);//通过反射得到注解类
//获取配置创建对象
Dept dept = context.getBean("dept", Dept.class);//获取User的class类,把接收到的object转化为User类
System.out.println(dept);
dept.show();
注解读取properties配置文件
@Value一般会被用在从properties配置文件中读取内容进行使用,具体如何实现?
@Configuration@ComponentScan("com.itheima")
@PropertySource("jdbc.properties")
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
@Value("${name}")
private String name;
public void save() {
System.out.println("book dao save ..." + name);
}
第三方注解bean管理
方式
第三方bean简单类型的依赖注入
第三方bean引用类型依赖注入
AOP(面向切面)
(1)面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能
底层原理
AOP底层使用了动态代理模式(可以转到设计模式笔记里面的代理模式,这里做简单叙述)
AOP操作术语
把通知应用到切入点的过程。(将增强代码(面)插入需要增强的方法(切入点)
代码实现
<?xml version="1.0" encoding="UTF-8"?>
<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>org.example</groupId>
<artifactId>spring2</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
</dependencies>
package com.kevin.dao.impl;
import com.kevin.dao.BookDao;
import org.springframework.stereotype.Repository;
@Repository
public class BookDaoImpl implements BookDao {
public void save(){
// System.out.println(System.currentTimeMillis());
System.out.println("book dao save ...");
}
public void update(){
System.out.println("book dao update ...");
}
package com.kevin.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan("com.kevin")
@EnableAspectJAutoProxy
public class SpringConfig {
package com.kevin.aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class MyAdvice {
@Pointcut("execution(void com.kevin.dao.BookDao.update())")
private void pt(){}
@Before("pt()")
public void method(){
System.out.println(System.currentTimeMillis());
}
package com.kevin;
import com.kevin.config.SpringConfig;
import com.kevin.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = ctx.getBean(BookDao.class);
bookDao.save();
}
AOP的工作流程
AOP切入点表达式
(1)切入点表达式格式:动作关键字(访问修饰符 返回值 路径(参数)异常名)
AOP通知获取数据
从原始方法获取参数
获取返回值
通知获取异常
数据处理代码实现
@Service
public class ResourcesServiceImpl implements ResourcesService {
@Autowired
private ResourcesDao resourcesDao;
@Override
public boolean openURL(String url, String password) {
System.out.println(password.length());
//在这调用数据层接口
return resourcesDao.readResources(url,password);
}
@Repository
public class ResourcesDaoImpl implements ResourcesDao {
@Override
public boolean readResources(String url, String password) {
//模拟校验
return password.equals("root");
}
@Component
@Aspect
public class DataAdvice {
@Pointcut("execution(boolean com.kevin.Service.*Service.*(*,*))")
private void pt(){}
@Around("pt()")
public Object trimStr(ProceedingJoinPoint pjp) throws Throwable {
//在原有方法前对字符串进行处理
//获取参数
Object[] args = pjp.getArgs();
for (int i =0;i<args.length;i++){
//判断是否为字符串
if (args[i].getClass().equals(String.class)){
//处理字符串
args[i] = args[i].toString().trim();
}
}
//执行原有方法,把改完的参数放回去
Object proceed = pjp.proceed(args);
//返回方法值
return proceed;
}
public class App {
public static void main(String[] args) {
ApplicationContext app =new AnnotationConfigApplicationContext(SpringConfig.class);
ResourcesService rs = app.getBean(ResourcesService.class);
boolean flag= rs.openURL("https://pan.baidu.com/haha", "root ");
System.out.println(flag);
}
spring-mybatis整合
实现思路 :dataSource<factory<session<dao<service
把mybatis一些创建对象引入资源等事情交给spring容器去完成,mybatis配置文件写一些设置就行
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 配置文件的根元素 -->
<configuration>
<!--设置:定义mybatis的一些全局属性-->
<settings>
<!--log4j-->
<!--<setting name="logImpl" value="LOG4J"/>-->
<!-- 自动映射行为 full全映射 none写啥映射啥 默认是partial 比none级别高-->
<setting name="autoMappingBehavior" value="FULL"/>
<setting name="jdbcTypeForNull" value="NULL"/>
<setting name="cacheEnabled" value="ture"/>
</settings>
<!--配置别名-->
<typeAliases>
<package name="com.user.model"/>
<package name="com.user.dao"/>
</typeAliases>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<property name="helperDialect" value="oracle"/>
</plugin>
</plugins>
<!-- 数据库环境交给spring配置-->
基础配置
完成model层,再编写接口以及实现类,编写mapper.xml文件
model
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class SmbmsUser {
private String id;
private String usercode;
private String username;
private String userpassword;
private String gender;
private java.sql.Date birthday;
private String phone;
private String address;
private String userrole;
private String createdby;
private java.sql.Date creationdate;
private String modifyby;
private java.sql.Date modifydate;
接口
List<SmbmsUser> getUserList() throws IOException;
SmbmsUser getUser(String id) throws IOException;
Integer addUser(SmbmsUser user);
Integer update(SmbmsUser user);
实现类
public class UserDao implements IUserDao {
String nameSpace = "com.user.dao.IUserDao";
// 由容器注入session
private SqlSessionTemplate sqlSession;
public SqlSessionTemplate getSqlSession() {
return sqlSession;
}
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public List<SmbmsUser> getUserList() throws IOException {
List<SmbmsUser> users = sqlSession.selectList(nameSpace + ".getUserList", SmbmsUser.class);
return users;
}
@Override
public SmbmsUser getUser(String id) throws IOException {
SmbmsUser user = sqlSession.selectOne(nameSpace + ".getUser", id);
return user;
}
@Override
public Integer addUser(SmbmsUser user) {
int insert = sqlSession.insert(nameSpace + ".addUser", user);
// 手动提交
sqlSession.commit();
return insert;
}
@Override
public Integer update(SmbmsUser user) {
int update = sqlSession.update(nameSpace + ".update", user);
sqlSession.commit();
return update;
}
@Override
public Integer delete(String id) {
int delete = sqlSession.delete(nameSpace + ".delete", id);
sqlSession.commit();
return delete;
}
mapper.xml
<?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="com.user.dao.IUserDao">
<resultMap id="user" type="smbmsUser">
<id property="id" column="ID"></id>
<result property="name" column="USERNAME"></result>
</resultMap>
<select id="getUserList" resultType="com.user.model.SmbmsUser">
select * from SMBMS_USER
</select>
<select id="getUser" resultMap="user" parameterType="java.lang.String">
select * from SMBMS_USER where id = #{id}
</select>
<insert id="addUser" parameterType="smbmsUser">
<![CDATA[
insert into SMBMS_USER
(ID,USERCODE,USERNAME,USERPASSWORD,GENDER,BIRTHDAY,PHONE,ADDRESS,USERROLE,CREATEDBY,CREATIONDATE)
values (#{id},#{usercode},#{name},#{userpassword},#{gender},#{birthday},#{phone},#{address},#{userrole},#{createdby},#{creationdate})
]]>
</insert>
<update id="update" parameterType="smbmsUser">
<![CDATA[
update SMBMS_USER
set
USERCODE=#{usercode},
USERNAME=#{name},
USERPASSWORD=#{userpassword},
GENDER=#{gender},
BIRTHDAY=#{birthday},
PHONE=#{phone},
ADDRESS=#{address},
USERROLE=#{userrole},
MODIFYBY=#{modifyby},
MODIFYDATE=#{modifydate}
where id = #{id}
]]>
</update>
<delete id="delete" parameterType="string">
<![CDATA[
delete from SMBMS_USER where ID= #{id}
]]>
</delete>
<!-- #{} 占位符,用于预编译-->
<!-- ${} sql拼接-->
在spring容器xml里面配置mybatis所需要的类与资源
1 引入外部文件(数据库配置文件)
<!-- 1 引入外部文件-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="druid.properties"></property>
2 配置数据源/池(value值需要与配置文件里面一致)
<!-- 2 配置数据源/池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
<property name="driverClassName" value="${driverClassName}"></property>
<property name="url" value="${url}"></property>
<property name="initialSize" value="${initialSize}"></property>
<property name="maxActive" value="${maxActive}"></property>
<property name="minIdle" value="${minIdle}"></property>
<property name="maxWait" value="${maxWait}"></property>
3 创建SqlSessionFactoryBean 建立数据库会话的工厂
<!-- 3 创建SqlSessionFactoryBean工厂-->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--3.1 配置连接池-->
<property name="dataSource" ref="dataSource"></property>
<!--3.2 配置mybatis文件-->
<property name="configLocation" value="mybatis-config.xml"></property>
<!--3.3 配置映射文件 因为配置文件不止一个,所以要用list-->
<property name="mapperLocations" >
<list>
<value>com/user/dao/mapper/userDaoMapper.xml</value>
</list>
</property>
4 创建session模型,用于注入到方法
<!-- 4 创建会话模型,用于注入到方法-->
<bean id="sessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="factory"></constructor-arg>
5 创建dao,service bean对象
<!-- 创建dao,service bean对象-->
<bean id="userDao" class="com.user.dao.Imp.UserDao">
<property name="sqlSession" ref="sessionTemplate"></property>
</bean>
<bean id="userService" class="com.user.service.Imp.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
如果dao接口没有实现类
4原第四步可以省略,直接传入第三步的session工厂给MapperFactory,让MapperFactory创建dao接口的子类(与原实现类为兄弟关系,要用dao接口接收),这个子类顶替原实现类,原实现类方法里面就只有创建session,然后用session去查询数据,这个步骤可以让容器来完成。
4 创建MapperFactoryBean
<!--创建MapperFactoryBean,方便被service层调用-->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<!--4.1 设置要实现的接口-->
<property name="mapperInterface" value="com.user.dao.IUserDao"></property>
<!--4.2 引入前面创建好的工厂,来创建会话,也可以传入创建好的session模型-->
<property name="sqlSessionFactory" ref="factory"></property>
5 创建service
<bean id="userService" class="com.user.service.Imp.UserService">
<property name="userDao" ref="userMapper"></property>
注解方式
自动扫描路径下的mapper接口,自动注册MapperFactoryBean(dao接口的子实现类)
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.*.dao"></property>
5 开启注解扫描
<!--开启注解扫描-->
<context:component-scan base-package="com"></context:component-scan>
6 给service层打上@service和属性自动装配
@Service
public class UserService implements IUserService {
@Autowired
private IUserDao userDao;
public IUserDao getUserDao() {
return userDao;
}
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
@Override
public List<SmbmsUser> getUserList() throws IOException {
return userDao.getUserList();
}
事务
事务四种隔离级别
- Read Uncommited,读未提交,即一个事务可以读取另一个未提交事务的数据;并发操作会导致脏读
- Read Commited,读操作,即一个事务要等到另一个事务提交后才能读取数据;解决脏读问题;并发操作会导致不可重复读
- Repeatable Read,重复读,即开始读取数据(事务开启)时,不再允许修改操作;解决不可重复读问题;并发操作会导致幻读(对应insert操作)
- Serializable,序列化,最高的事务隔离级别,该级别下,事务串行化顺序执行;避免脏读、不可重复读与幻读;但是该级别效率低下,比较消耗数据库性能,一般不用。
事务七种传播机制
<!-- 配置事务 -->
<!--1 配置事务管理器的bean -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--传入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--2 配置事务增强 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED"/>
<tx:method name="get*" isolation="DEFAULT" propagation="REQUIRED"/>
<tx:method name="delete*" isolation="DEFAULT" propagation="REQUIRED"/>
<tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--3 配置切面 将事务增强与切入点进行绑定 -->
<aop:config>
<!--2.1 配置切入点 -->
<aop:pointcut id="pointcut" expression="execution(public * com.*.service.*.*(..))"/>
<!--2.2 将两者进行绑定 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"></aop:advisor>
代码实现
public class Account implements Serializable {
private Integer id;
private String name;
private Double money;
//set..get...
package com.kevin.dao;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
public interface AccountDao {
@Update("update spring3 set money = money + #{money} where name = #{name}")
void inMoney(@Param("name") String name, @Param("money") Double money);
@Update("update spring3 set money = money - #{money} where name = #{name}")
void outMoney(@Param("name") String name, @Param("money") Double money);
@Transactional
public interface AccountService {
/**
* 转账操作
* @param out 传出方
* @param in 转入方
* @param money 金额
*/
public void transfer(String out,String in ,Double money) ;
}
//实现类
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
public void transfer(String out,String in ,Double money) {
accountDao.outMoney(out,money);
int i = 1/0;
accountDao.inMoney(in,money);
}
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/kevin_01?useSSL=false
jdbc.username=root
import javax.sql.DataSource;
public class JDBCConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String userName;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
import javax.sql.DataSource;
public class MybatisConfig {
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
ssfb.setTypeAliasesPackage("com.kevin.domain");
ssfb.setDataSource(dataSource);
return ssfb;
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.kevin.dao");
return msc;
}
@Configuration
@ComponentScan("com.kevin")
@PropertySource("classpath:jdbc.properties")
@Import({JDBCConfig.class,MybatisConfig.class})
public class SpringConfig {
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
@Autowired
private AccountService accountService;
@Test
public void testTransfer() throws IOException {
accountService.transfer("tom","jery",100D);
}
//2.1 开启注解事务
@Transactional
public interface AccountService {
/**
* 转账操作
* @param out 传出方
* @param in 转入方
* @param money 金额
*/
public void transfer(String out,String in ,Double money) ;
public class JDBCConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String userName;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
//2.2 配置事务管理器,mybatis使用的是jdbc事务
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
@Configuration
@ComponentScan("com.kevin")
@PropertySource("classpath:jdbc.properties")
@Import({JDBCConfig.class,MybatisConfig.class})
//2.3 开启注解式事务驱动
@EnableTransactionManagement
public class SpringConfig {
事务角色
加入事务方,在spring中通常指代数据层方法,也可以指代业务层方法