一榔捶
Spring
Spring框架概述
1、Spring是轻量级的开源的JavaEE框架
2、Spring可以解决企业应用开发的复杂性
3、Spring有两个核心组成部分:IOC和AOP
(1)、IOC:控制反转,把创建对象过程交给Spring进行管理降低耦合度
IOC底层原理:XML解析、工厂模式、反射
(2)、AOP:面向切面,不修改源代码进行功能增强
4、Spring 特点
(1)、方便解耦,简化开发
(2)、Aop 编程支持
(3)、方便程序测试
(4)、方便和其他框架进行整合
(5)、方便进行事务操作
(6)、降低 API 开发难度
5、代码块的编写
创建普通方法–创建Spring配置文件,在配置文件配置创建的对象XML-config…Spring.xml----测试代码编写:加载Spring配置文件(ApplicationContext)
public class User{
public void add(){
System.out.println("add.....")
}
}
<?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="day1.User"></bean>
public class User {
public void add(){
System.out.println("add........");
}
}
@Test
public void testAdd1() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
User user = context.getBean("user", User.class);
System.out.println(user);
user.add();
}
6、IOC思想
1、IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
2、Spring提供IOC容器实现两种方式:(两个接口)
(1)、BeanFactory:IOC容器的基本实现,是Spring的内部借口,加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
(2)、ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,由开发人员使用,加载配置文件时候就已经把配置文件的对象进行创建了。
3、IOC操作Bean管理
(0)、Bean管理指的是两个操作
(1)、Spring创建对象
(2)、Spring注入属性
4、Bean管理操作有两种方式
(1)、基于xml配置文件方法实现
(2)、基于注解方式实现
使用set方法进行注入
public class Book {
private String bName;
private String bauthor;
public void setbName(String bName) {
this.bName = bName;
}
public void setBauthor(String bauthor){
this.bauthor = bauthor;
}
public void testDemo(){
System.out.println(bName+"::::::"+bauthor);
}
}
@Test
public void testBook(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Book book = context.getBean("book", Book.class);
System.out.println(book);
book.testDemo();
}
<bean id="book" class="day1.Book">
<!-- 使用property完成属性注入 -->
<property name="bName" value="易筋经"></property>
<property name="bauthor" value="达摩老祖"></property>
</bean>
使用有参构造进行注入(constructor-arg)
public class Orders {
private String oName;
private String address;
//有参数构造
public Orders(String oName,String address){
this.oName=oName;
this.address=address;
}
public void orderTest(){
System.out.println(oName+":::::"+address);
}
}
<bean id="orders" class="day1.Orders">
<constructor-arg name="oName" value="啦啦啦"></constructor-arg>
<constructor-arg name="address" value="China"></constructor-arg>
</bean>
@Test
public void testOrders(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println(orders);
orders.orderTest();
}
7、IOC操作Bean管理
1、xml注入其他类型的属性
(1)、null值:
<property name="address">
<null/>
</property>
(2)、属性中包含特殊符号,例如:<>
<property name="address">
<value>
<![CDATA[<<南京>>]]>
</value>
</property>
2、注入属性-外部的bean
(1)、创建两个类service类和dao类
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
public void add(){
System.out.println("service add.......");
userDao.update();
}
}
public interface UserDao {
public void update();
}
public class UserDaoImpl implements UserDao {
@Override
public void update() {
System.out.println("dao update ............");
}
}
(2)、service中调用dao方法
private UserDao userDao;
(3)、在springxml文件中进行配置(利用ref放入property中)
<!-- 外部bean的注入:::::::::::-->
<bean id="userService" class="day2.service.UserService">
<!-- 注入userDao对象
name属性:类里面属性名称
ref属性:创建userDao对象bean标签id值
使用ref让一个Bean作为另一个Bean的成员变量(属性)
-->
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="day2.dao.UserDaoImpl"></bean>
3、注入属性-内部的bean
(1)、一对多关系:部门(Dept)和员工(Emp),一个部门有多个员工,一个员工属于一个部门
(2)、在实体类之间表示一对多关系,员工表示所属部门,使用对象类型进行表示
public class Dept {
private String dName;
public void setdName(String dName) {
this.dName = dName;
}
@Override
public String toString() {
return "Dept{" +
"dName='" + dName + '\'' +
'}';
}
}
public class Emp {
private String eName;
private String gender;
private Dept dept;
public Dept getDept() {
return dept;
}
public void seteName(String eName) {
this.eName = eName;
}
public void setGender(String gender) {
this.gender = gender;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public void add(){
System.out.println(eName+"::::"+gender+"::::"+dept.toString());
}
}
<bean id="emp" class="day2.bean.Emp">
<!-- 设置两个普通属性-->
<property name="eName" value="lucy"></property>
<property name="gender" value="女"></property>
<!-- 设置对象类型属性-->
<property name="dept">
<bean id="dept" class="day2.bean.Dept">
<property name="dName" value="安保"></property>
</bean>
</property>
</bean>
tips:使用内嵌方法进行SpringXml文件的配置
4、注入属性-级联赋值
<!--级联赋值-->
<bean id="emp" class="day2.bean.Emp">
<property name="eName" value="123"></property>
<property name="gender" value="女"></property>
<property name="dept" ref="dept"></property>
<property name="dept.dName" value="大哥"></property><!-- 需要get方法 -->
</bean>
<bean id="dept" class="day2.bean.Dept">
<!-- <property name="dName" value="财务"></property>-->
</bean>
其中,第二种方法中的"dept.dName"需要Emp中的dept类的属性的get方法
5、注入属性-集合、数组、列表属性
创建类、定义数组、list、map、set类型属性,生成对应的set方法
public class collectionType {
//数组类型属性
private String[] courses;
//list集合类型属性
private List<String> list;
//map集合型属性
private Map<String,String> map;
//set属性
private Set<String> sets;
//学生学的多门课程
private List<course> courseList;
public void setCourseList(List<course> courseList){
this.courseList = courseList;
}
public void setSets(Set<String> sets) {
this.sets = sets;
}
public void setCourses(String[] courses){
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public void add(){ System.out.println(Arrays.toString(courses)+":::"+list+":::"+map+":::"+sets);
System.out.println(courseList);
}
}
public class course {
private String cName;
public void setcName(String cName) {
this.cName = cName;
}
@Override
public String toString() {
return "course{" +
"cName='" + cName + '\'' +
'}';
}
}
<bean id="collect" class="day3.collectionType">
<property name="courses">
<array>
<value>123414</value>
<value>12421441251</value>
</array>
</property>
<property name="list">
<list>
<value>zhangyulong</value>
<value>renwangba</value>
</list>
</property>
<property name="map">
<map>
<entry key="123" value="456"></entry>
</map>
</property>
<property name="sets">
<set>
<value>Mysql</value>
<value>Redis</value>
</set>
</property>
当注入的值为对象时,xml文件配置如下:
<!--注入list集合类型,值是对象-->
<property name="courseList">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<bean id="course1" class="day3.course">
<property name="cName" value="nande"></property>
</bean>
<bean id="course2" class="day3.course">
<property name="cName" value="nvde"></property>
</bean>
6、提取集合注入部分
将xmlns:schemaLocation中的beans改为util(复制后),然后借助ref进行提取使用
<?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"
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>lalala</value>
<value>hahaha</value>
<value>houhouhou</value>
</util:list>
<bean id="book" class="day3.Book">
<property name="list" ref="bookList"></property>
</bean>
</beans>
7、工厂FactoryBean
1、Spring类型分为两种bean,一种是普通bean,另一种是工厂bean(FactoryBean)
普通bean:在配置文件中定义bean类型就是返回类型
工厂bean:在配置文件中定义bean类型可以和返回类型不一样
第一步:创建类,让这个类作为工厂bean,实现接口FactoryBean
第二部:实现接口里面的方法,在实现的方法中定义返回的bean类型
public class MyBean implements FactoryBean<course> {
@Override
public course getObject() throws Exception {
course cours = new course();
cours.setcName("abc");
return cours;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
<bean id="myBean" class="day3.factoryBean.MyBean">
</bean>
@Test
public void test3(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean7.xml");
course course = context.getBean("myBean", course.class);
System.out.println(course);
}
8、bean作用域(单实例和多实例)关键词:scope=“prototype”
1、在Spring里,设置创建bean实例是单实例还是多实例
2、在Spring里,默认情况下是单实例
public class Book {
private List<String> list;
public void setList(List<String> list){
this.list = list;
}
public void add(){
System.out.println(list);
}
}
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean6.xml");
Book book1 = context.getBean("book", Book.class);
Book book2= context.getBean("book",Book.class);
System.out.println(book1);
System.out.println(book2);
book1.add();
book2.add();
}
<util:list id="bookList">
<value>lalala</value>
<value>hahaha</value>
<value>houhouhou</value>
</util:list>
<bean id="book" class="day3.Book" scope="prototype">
<property name="list" ref="bookList"></property>
</bean>
8、bean的生命周期
1、生命周期概念
(1)、从对象创建到对象销毁的过程
2、bean生命周期
(1)、通过构造器创建bean实例(无参数构造)
(2)、声明一个私有属性,为bean的属性设置值(调用set方法)
(3)、调用bean的初始化方法(xml文件中进行配置)(init-method=“ ”)
(4)、bean可以使用
(5)、调用销毁方法(同样需要进行xml文件配置)(destory-method=“ ”)
3、演示bean生命周期
public class Orders {
public Orders(){
System.out.println("1、执行无参构造创建bena实例");
}
private String oneName;
public void setOneName(String oneName){
System.out.println("2、调用set方法设置属性");
this.oneName = oneName;
}
public void initMethod(){
System.out.println("4、执行初始化方法");
}
public void destoryMethod(){
System.out.println("7、执行销毁方法");
}
}
<bean id="orders" class="day4.Orders" init-method="initMethod" destroy-method="destoryMethod">
<property name="oneName" value="张大帅"></property>
</bean>
//后置处理器
<bean id="myBeanPost" class="day4.MyBeanPost"></bean>
@Test
public void testOrders(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean8.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println("6、获取创建的bean实例对象");
System.out.println(orders);
orders.destoryMethod();
}
添加后置处理器
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("3、初始化之前执行的方法");
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("5、初始化之后执行的方法");
return null;
}
}
1、执行无参构造创建bena实例
2、调用set方法设置属性
3、初始化之前执行的方法
4、执行初始化方法
5、初始化之后执行的方法
6、获取创建的bean实例对象
day4.Orders@4e718207
7、执行销毁方法
9、xml自动装配
1、什么是自动装配
(1)、根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值注入
2、演示自动装配过程
(1)、根据属性名称自动注入
bean标签中 autowire进行自动装配
autowire=“byName”:根据属性名称注入,注入值bean的id值和类属性名称一样
Autowire=“byType”:根据属性类型一样
10、引入外部属性文件(Druid连接)
1、直接配置数据库信息
(1)、配置Druid连接池
(2)、引入Druid连接池依赖jar包
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 http://www.springframework.org/schema/context/spring-context.xsd">
<!-- <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">-->
<!-- <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>-->
<!-- <property name="url" value="jdbc:mysql://localhost:3306/book?characterEncoding=utf8"></property>-->
<!-- <property name="username" value="root"></property>-->
<!-- <property name="password" value="374761727"></property>-->
<!-- </bean>-->
<!-- 引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.Password}"></property>
</bean>
Tips:其中context需要进行修改,xmlns:context以及xsi:schemaLocation
创建外部文件:jdbc.properties
prop.driverClass=com.mysql.cj.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/book?characterEncoding=utf8
prop.userName=root
prop.Password=374761727
11、基于注解方式进行Bean管理
1、什么是注解
(1)、注解是代码特殊标记,格式:@注解名称(属性名称=属性值)
(2)、使用注解,注解作用在类上面,方法上面,属性上面
(3)、使用注解目的:简化xml配置
2、Spring针对Bean管理中创建对象提供注解
(1)、@Component:普通组件
(2)、@Service:业务层组件
(3)、@Controller:控制层组件
(4)、@Repository:持久层组件
tips:以上四种注解可在任意功能时进行使用,都可以用来创建bean实例
3、基于注解方式实现对象的创建
(1)、引入依赖
Spring-aop-5.2.6.RELEASE.jar
(2)、开启组件扫描**(如果是多个包,使用逗号隔开)**
<context:component-scan base-package="day4">
</context:component-scan>
(3)、创建类,并在类的上方添加创建对象的注解
@Service//<bean id="userService" class="..">
public class UserService {
@Autowired//需要为UserDaoImpl实现类中也加入注解@实现对象创造
private UserDao userDao;
public void add(){
System.out.println("add........");
userDao.add();
}
}
(4)、开启组件扫描细节配置(filter为过滤器,include-filter设置扫描哪些内容)
<context:component-scan base-package="com.atguigu" use-default-
filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
(5)、基于注解方式实现属性注入
第一步:创建service和dao对象,在两个类中添加对象注解
第二步:在service中注入dao对象,在service类中添加dao的类型属性
@Autowired:根据属性类型进行自动装配
@Qualifier:根据名称进行引入,需要和@Autowired一起使用,并借用value
@Resource:可以根据类型注入,也可以根据名称注入,属于注解包不属于Spring包
@Value:注入普通类型属性
@Service//<bean id="userService" class="..">
public class UserService {
@Autowired//需要为UserDaoImpl实现类中也加入注解@实现对象创造
private UserDao userDao;
public void add(){
System.out.println("add........");
userDao.add();
}
}
public interface UserDao {
public void add();
}
@Repository(value = "userDaoImpl1")
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("Dao add........");
}
}
@Test
public void testUserService(){
//采用注解的方式
ApplicationContext context = new ClassPathXmlApplicationContext("bean10anno@.xml");
//查找目录下所有带@四项的注解
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
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 http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="day4">
</context:component-scan>
12、完全配置开发(完全使用注解方式)
1、创建配置类,取代xml文件,@Configuration@ComponentScan(basePackages={" "})
@Configuration
@ComponentScan(basePackages={"day4"})
public class SpringConfig {
}
2、编写测试类
@Test
public void testUserservice(){
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
第二部分:AOP
1、什么是AOP
(1)、面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使业务中各业务之间的逻辑之间的耦合度降低,提高程序可用性,并提高开发的效率
(2)、通俗描述:不通过修改源代码的方式,在主干功能中添加新功能
2、JDK动态代理
1、使用JDK动态代理,使用Proxy类里面的方法创建代理对象
(1)、调用newProxyInstance方法
方法中有三个参数:
第一参数:类加载器-当前类的:Proxy
第二参数:增强方法所在的类(Dao),这个类实现的接口(Impl),支持多个接口
第三参数:实现这个接口InvocationHandler,创建代理对象,写增强的那部分代码
(2)、编写JDK动态代理代码
创建接口,定义方法
public interface UserDao {
public int add(int a,int b);
public String update(String id);
}
创建接口实现类,实现方法
public class UserDaoImpl implements UserDao {
@Override
public int add(int a, int b) {
return a+b;
}
@Override
public String update(String id) {
return id;
}
}
使用Proxy类创建接口代理对象(程序的入口)
public class JDkProxy {
public static void main(String[] args) {
Class[] interfaces = {UserDao.class};
UserDaoImpl userDaoImpl = new UserDaoImpl();
UserDao userDao = (UserDao) Proxy.newProxyInstance(JDkProxy.class.getClassLoader(),//1
interfaces, new UserDaoProxy(userDaoImpl));
int result = userDao.add(8, 9);
System.out.println(result);
}
}
UserDaoProxy对象
public class UserDaoProxy implements InvocationHandler {
private Object obj;//UserDaoImpl的arg,由1到此处
public UserDaoProxy(Object obj) {
this.obj=obj;
}
@Override
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
System.out.println("方法完成前:"+method.getName()+ Arrays.toString(args));
Object invoke = method.invoke(obj, args);
System.out.println("behiend:"+obj);
return invoke;
}
}
3、AOP的术语及常用说法
1、连接点
概念:类中那些方法可以被增强,称为连接点。(基本所有的类都可以作为连接点)
2、切入点
概念:实际真正的被增强的方法被叫做切入点
3、通知(增强)
概念:实际增强的方法的逻辑的部分称为通知(增强)
通知具有多种类型:
- 前置通知(@Before)
- 后置通知 (@AfterReturning)
- 环绕通知(@Around)
- 异常通知(@AfterThrowing)
- 最终通知(@After)
4、切面
概念:把通知应用到切入点的过程,即将增强的方法应用到被增强的方法中
4、AOP操作(准备工作)
1、Spring框架一般基于 AspectJ 实现AOP操作
AspectJ 不是Spring组成部分,它独立于AOP框架,一般把AspectJ 和 Spring框架一起使用,进行AOP操作
2、基于AspectJ实现AOP操作
两种方法:基于xml以及基于注解,通常情况下我们使用基于注解的方法实现
3、引入依赖
spring-aspects-5.2.6.RELEASE.jar
以及Springsource三个jar包
4、切入点的表达式
- 可以知道对哪个类中的哪个方法进行增强
- 语法结构:execution([权限修饰符] [返回类型] [类全路径] 方法名称 )
例如:execution( day5.AopAnno.Proxy.User.add(…))*
5、AOP操作(具体步骤)
1、创建类,在类中定义一个add()方法
//被增强的类
@Component
public class User {
public void add(){
System.out.println("add........");
}
}
2、增强的类的方法UserProxy**(两个类中均实现注解,即@Component那四个注解)**
//增强的类的方法
@Component
@Aspect
public class UserProxy {
@Before(value = "execution(* day5.AopAnno.Proxy.User.add(..))")
public void before(){
System.out.println("before......");
}
@AfterReturning(value = "execution(* day5.AopAnno.Proxy.User.add(..))")
public void afterReturning(){
System.out.println("afterReturning....");
}
@After(value = "execution(* day5.AopAnno.Proxy.User.add(..))")
public void after(){
System.out.println("After.....");
}
@AfterThrowing(value = "execution(* day5.AopAnno.Proxy.User.add(..))")
public void afterThrowing(){
System.out.println("AfterThrowing.....");
}
@Around(value = "execution(* day5.AopAnno.Proxy.User.add(..))")
public void arround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
System.out.println("Around....环绕之前");
proceedingJoinPoint.proceed();
System.out.println("Around....环绕之后");
}
}
3、开启注解扫描,在Spring配置文件中,其中@Aspect在增强类上实现
<context:component-scan base-package="day5.AopAnno">
</context:component-scan>
<!--开启Aspect生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4、相同的切入点抽取
@Pointcut(value = "execution(* day5.AopAnno.Proxy.User.add(..))")
public void pointdemo(){
}
5、有多个增强类对同一个方法进行增强,设置增强类优先级
在增强类上面添加注解
@Order(数字类型值),数字类型值越小优先级越高
第三部分:JdbcTemplate
1、什么是JdbcTemplate
1、Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库进行操作
2、准备工作
(1)、引入相关jar包
Spring-jdbc-5.2.6.RELEASE.jar、Spring-orm-5.2.6.RELEASE.jar、Spring-tx-5.2.6.RELEASE.jar
(2)、在Spring配置文件中配置数据库连接池
<!-- 引入外部属性文件-->
<!-- <context:property-placeholder location="classpath:jdbc.properties"/>-->
<!-- 配置连接池-->
<context:component-scan base-package="day6NoFinal"></context:component-scan>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.Password}"></property>
</bean>
<!--配置JdbcTemplate对象,注入DataSource-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
jdbc.properties如下
prop.driverClass=com.mysql.cj.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/book?characterEncoding=utf8
prop.userName=root
prop.Password=374761727
(3)、创建Book、Service、Dao、Impl类并在dao中注入jdbcTemplate对象
public class Book {
private String userId;
private String username;
private String ustatue;
public void setUserId(String userId) {
this.userId = userId;
}
public void setUsername(String username) {
this.username = username;
}
public void setUstatue(String ustatue) {
this.ustatue = ustatue;
}
public String getUserId() {
return userId;
}
public String getUsername() {
return username;
}
public String getUstatue() {
return ustatue;
}
}
@Service
public class BookService {
@Autowired
private BookDao bookDao;
public void addBook(Book book){
bookDao.add(book);
}
public void updateBook(Book book){
bookDao.update(book);
}
public void deleteBook(Book book){
bookDao.delete(book);
}
}
@Repository
public interface BookDao {
public void add(Book book);
void update(Book book);
void delete(Book book);
}
3、JdbcTemplate操作数据库
@Repository
public class BookDaoImpl implements BookDao {
//注入JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void add(Book book) {
String sql = "insert into t_book1 values(?,?,?)";
int update = jdbcTemplate.update(sql,book.getUserId(), book.getUsername(), book.getUstatue());
System.out.println(update);
}
@Override
public void update(Book book) {
String sql = "update t_book1 set username=?,ustatue=? where userId=?";
int update = jdbcTemplate.update(sql, book.getUsername(), book.getUstatue(), book.getUserId());
System.out.println(update);
}
@Override
public void delete(Book book) {
String sql = "delete from t_book1 where userId = ?";
int update = jdbcTemplate.update(sql, book.getUserId());
System.out.println(update);
}
}
测试类
public class testJdbcTemplate {
@Test
public void test(){
ApplicationContext context =
new ClassPathXmlApplicationContext("bean12.xml");
BookService bookService = context.getBean("bookService", BookService.class);
Book book = new Book();
book.setUserId("1");
book.setUsername("142");
book.setUstatue("sfsa");
bookService.addBook(book);
}
@Test
public void tes1(){
ApplicationContext context =
new ClassPathXmlApplicationContext("bean12.xml");
BookService bookService = context.getBean("bookService", BookService.class);
Book book = new Book();
book.setUserId("1");
book.setUsername("111111");
book.setUstatue("2222222");
bookService.addBook(book);
}
@Test
public void test2(){
ApplicationContext context =
new ClassPathXmlApplicationContext("bean12.xml");
BookService bookService = context.getBean("bookService", BookService.class);
Book book = new Book();
book.setUserId("1");
bookService.deleteBook(book);
}
}
jdbcTemplate操作数据库(查询返回某个值)
@Override
public int selectCount() {
String sql = "select count(*) from t_book";
Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
return count;
}
jdbcTemplate操作数据库(查询返回对象)
其中RowMapper是接口,针对返回不同类型的数据,使用这个接口里面的实现类完成数据封装,其中使用到了匿名实现类
@Override
public Book findBookInfo(String id) {
String sql = "select * from t_book where user_id=?"; //调用方法
Book book = jdbcTemplate.queryForObject(sql, new
BeanPropertyRowMapper<Book>(Book.class), id);
return book;
}
jdbcTemplate操作数据库(查询返回集合)
public List<Book> findAllBook() {
String sql = "select * from t_book";
//调用方法
List<Book> bookList = jdbcTemplate.query(sql, new
BeanPropertyRowMapper<Book>(Book.class));
return bookList;
}
第四部分:事务
1、什么是事务
(1)、基本操作
事务是数据库操作最基本单元,绑定于上一组操作,要么都成功,要么都失败,一荣俱荣,一损俱损。
(2)、典型场景
银行转账:
- lucy转账100元给mary
- lucy少100,mary多100元
(3)、事务四个特性(ACID)
- 原子性
- 一致性
- 隔离性
- 持久性
(4)、事务操作(搭建事务操作环境)
2、创建数据库表t_book,添加记录
userid | username | money |
---|---|---|
1 | lucy | 1000 |
2 | mary | 1000 |
3、创建service,搭建dao,完成对象创建和注入关系
(1)service注入dao,在到注入JdbcTemplate,在JdbcTemplate注入DataSource
@Service
@Transactional
public class UserService {
@Autowired
private UserDao userDao;
public void accountMoney(){
userDao.addMoney();
//模拟错误
// int i = 10/0;
userDao.reduceMoney();
}
}
public interface UserDao {
public void addMoney();
public void reduceMoney();
}
实现两个方法,多钱和少钱的方法,并在service中创建方法(转账:见代码1)
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void reduceMoney() {
String sql = "update t_account set money=money-? where username=?";
jdbcTemplate.update(sql,100,"lucy");
}
@Override
public void addMoney() {
String sql = "update t_account set money=money+? where username=?";
jdbcTemplate.update(sql,100,"mary");
}
}
模拟错误后,第一条命令执行,第二条命令由于错误并未执行,故此我们引入事务的概念
4、事务操作
1、事务添加到JavaEE三层结构里面Service层(业务逻辑层)
2、在Spring进行事务管理操作
(1)、有两种方式:编程试事务管理和声明式事务管理(使用)
3、声明式事务管理方式
(1)、基于注解方式
(2)、基于xml配置文件方式
4、在Spring中进行声明式事务管理,底层使用AOP原理
5、Spring事务管理API
(1)、提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
5、基于声明式事务管理
1、在spring配置文件配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
2、在spring配置文件,开启事务注解
(1)、在spring配置文件引入名称空间tx
<?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"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.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">
<!-- 引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置连接池-->
<context:component-scan base-package="day7"></context:component-scan>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.Password}"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启事务的注解,并指定名字为transactionManager-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>
(2)、开启事务注解
<!-- 开启事务的注解,并指定名字为transactionManager-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
3、在service类上面(或者service类里面方法上面)添加事务注解
(1)、@Transactional,这个注解添加到类上面,也可以添加方法上面
(2)、如果把这个注解添加到类上面,这个类里面所有的方法都添加事务
(3)、如果把这个注解添加方法上面,为这个方法添加事务
4、事务操作(声明式事务管理参数配置‘六项’)
(1)、propagation:事务传播行为
概念:多事务方法直接进行调用,这个过程中事务是如何进行管理的
形式:@Transactional(propagation = Propagation.REQUIRED)
例如:有两个类add()、和update(),其中add()加入事务注解@Transactional
-
REQUIRED
如果add方法本身有事务,调用update方法之后,update使用当前add方法里面的事务,如果add方法本身没有事务,则调用update方法后,创建新事务
-
REQUIRED_NEW
使用add()方法调用update()方法,无论add()方法是否有事务,都创建新事务
-
SUPPORTS
如果有事务在运行中,当前的方法就在这个事务内运行,否则不可运行在事务中
-
NOT_SUPPORTE
-
MANDATPORY
-
NEVER
-
NESTED
(2)、isolation:事务隔离级别
概念:事务有特性称为隔离性,多事务操作之间不会产生影响,不考虑隔离性回产生很多问题:如下
-
脏读:一个未提交的事务读取到了另一个未提交事务但已修改数值的数据(回滚了)
由于事务回滚,并未提交的数据60000被东方不败所提取到
-
不可重复读:一个未提交事务读取到另一提交事务修改的数据
在东方不败未提交事务的时候,岳不群已经提交了事务,导致东方不败再一次获取到了岳不群事务提交后修改的数据
-
幻读:一个未提交事务读取到另一提交事务所添加的数据(与上同理)
解决:通过设置事务隔离级别,解决问题
形式为:@Transactional(isolation = Isolation.REPERTABLE_READ)
(3)、timeout:超时时间
(1)事务需要在一定时间内进行提交,如果不提交进行回滚
(2)默认值是 -1 ,设置时间以秒单位进行计算
(4)、readOnly:是否只读
(1)读:查询操作,写:添加修改删除操作
(2)readOnly 默认值 false,表示可以查询,可以添加修改删除操作
(3)设置 readOnly 值是 true,设置成 true 之后,只能查询
(5)、rollbackFor:回滚
(1)设置出现哪些异常进行事务回滚
(6)、noRollbackFor:不回滚
(1)设置出现哪些异常不进行事务回滚
第五部分:Spring5新特性
留待SpringMVC后进行分解