*创建Spring框架hello world项目的过程:
1.导入项目所需的最小配置的jar包:共5个,一个日志包,剩下四个为:core,context,bean,expression
2.创建各种你应用程序需要的beans
3.在src目录下,创建Spring的bean配置文件,并且在其中配置你要配置的beans
4.在需要获取bean的地方,首先获取应用程序上下文(bean的IoC容器),然后获取需要的bean
(其实,很简单,就是把你的beans写进配置文件,然后通过配置文件获取beans,而不是直接创建beans)
*配置bean的方式?
*使用XML配置bean的方式?
*使用全类名配置
0.配置id(id在同一个应用上下文(bean容器)中得是唯一的),配置class
1.使用全类名配置:这种方式使用的是反射的方式创建bean,使用反射的话有一个注意的地方,那就是被配置的bean得有一个无参的构造器,如果没有的话,报错
2.如果注入的属性字面值包含特殊的属性,则需要<![CDATA[**]]>和Value子节点包含起来
3.如果需要注入的属性是引用类型,则在配置property子节点时时不能用value属性,因为value配置的是字面值,得用ref属性,ref指向一个引用数据类型
4.当然,也可以在property子节点中不使用ref属性,而是使用ref子节点,然后在ref子节点中使用bean属性,或者直接上值来配置引用类型
5.当然配置引用属性时,也可以不使用外部bean,直接在property子节点内部创建一个bean子节点,该bean称为内部bean,只能在这个地方使用,不能在外部其他地方使用
6.可以为引用属性配置Null值,即使用<null/>
7.可以为级联属性赋值,那什么是级联属性呢?譬如A类依赖于B类,所以在bean容器中就需要把B注入到A中,通常呢,我们会给A类属性赋值,但是能不能给B也赋值呢?当然可以。首先,你需要先注入B,然后使用B的id点上属性进行赋值即可,使用的还是property子节点,那B自己注入的属性和后来级联注入的属性哪个覆盖哪个呢?是后来的级联覆盖一开始的属性注入。简单来说,级联属性即使属性的属性,
Spring中要为级联属性赋值,属性必须不为空,才能为这个属性的属性赋值,否则会报错,不同于Struts2
8.如何配置集合属性?同样使用property子节点,但是既不能使用Value属性,也不能使用ref属性,那使用什么呢?使用list子节点,然后在list子节点中配置ref子节点,在ref中配置bean属性来达到配置集合的效果,同理可以配置set,map等集合类,set和list几乎一样,map有点不一样,因为map是键值对类型,其具体配置如下:首先在property子节点中放一个map子节点,然后在map中放键值对,
使用entry子节点,通过配置该子节点的key和key-ref属性(key-value)来达到配置map的效果,同理,配置properties,使用property子节点,然后使用props子节点,然后使用prop子节点,然后使用key属性和直接上值的方式实现
9.如何注入数组属性呢?同理,使用第八条中的list
10.配置单例的集合bean,以供多个bean进行引用,很简单只需要引入util命名空间,然后使用这个命名空间里的list节点,为list节点配置以下id和bean啦,ref啦一些子节点就OK了,然后在注入集合属性的时候,直接使用ref属性就好
11.使用p命名空间为bean属性赋值,这样做是为了简化XML的配置,导入p明明空间后,直接在bean配置中使用p:prop(-ref)的方式来配置属性即可,仅仅是简化了XML的配置而已。完全可以使用P命名空间进行配置,这样简单很多,跟使用property子节点来比,功能上一样,但是写法上就简单很多了,实际开发中使用较多
12.bean的继承,这里的继承并不是面向对象中的继承,而是配置信息的继承,使用bean的parent属性可以继承某一个bean的配置,对于继承中想要重写的部分,直接对要重写的属性进行重写即可,继承和手动配置可以同时存在,和自动装配与手动装配一样,都是手动装配优先;对于bean的继承,还可以配置bean模板,也就是说这个bean就是专门用来被继承的,只需使用bean的abstract属性,设置为TRUE,
就表示这个bean是一个抽象bean,不能被实例化哦,若一个bean的class属性没有被指定,那这个bean必须被指定为抽象bean,并不是bean的所有属性都会被继承
13.配置依赖关系,使用bean的depends-on属性,被依赖的bean会在此bean创建好之前创建好
*使用自动装配(这里的装配并不是bean的装配,而是bean的属性的装配方式)
0.对单个bean配置时使用自动装配,即使用bean的autowire属性进行自动装配,如果属性值为『byName』,那进行自动装配时,就会把bean的id和被装配bean属性名称相同的bean(还是看setter)装配到这个bean的属性中来,如果没有和属性名称相同的bean id,则对于这个属性装配一个Null进去;如果属性值为『byType』,也会进行自动装配,按照类型进行自动装配,但是有一个问题,如果匹配到的类型
有多个,则抛出异常
1.使用自动装配之后,对于能自动装配的,而且没有异议的自动装配,会自动完成装配,对于不能自动装配的,可以补充手动装配,换言之,可以同时使用自动装配和手动装配,两者互为补充,但是如果两者发生了冲突,譬如:自动装配和手动装配动能装配成功,那这个时候怎么办呢?OK,手动装配优先级高于自动装配(比较符合人的思维吧,自动总是提前完成&手动说明你就是想覆盖掉自动
装配咯,你都指明了自动装配,然后补充了手动装配,正常思维来讲,手动装配的确应该高于自动装配,事实的确如此)
2.在实际开发中使用自动装配的时候并不多,方便了自己,但是明确清晰的配置文档更好一些
*通过工厂方法配置
*使用静态工厂方法(静态 工厂方法)
1.直接调用某一个类的静态方法,就可以返回这个类的实例
2.首先得编写一个工厂类,并创建一个静态方法用于获取对象
3.在XML中配置时,bean节点的class属性为工厂类,Factory-method方法配置静态方法,如果该静态方法需要参数传进去,则使用constructor-arg子节点传值
*使用实例工厂方法(实例工厂 方法)
1.实例工厂方法,就是一个实例工厂,调用该工厂的某个方法返回类的实例
2.首先编写一个工厂类,并创建工厂方法用于获取对象
3.在XML中配置时,首先配置工厂,因为工厂也是要被实例化的呀,就一般配置bean的方式配置工厂类即可,然后配置目标bean的时候,不用配置class了,通过配置factory-bean和factory-method两个属性来配置即可
*通过FactoryBean配置
*首先呢,FactoryBean是Spring自带的一个接口,这个接口呢总共三个抽象方法,一个是返回对象,一个是返回对象类型,一个是返回是否单例
*要想通过FactoryBean来配置bean,首先得有一个自己的FactoryBean,这个自定义的还要实现这个接口的三个方法
*然后在XML中配置:就是普通的配置bean,class就配FactoryBean,如果需要传什么参数进去的话,参数是FactoryBean的参数。使用property或者p命名空间传就行了,和使用全类名配置在形式上没什么区别
*就从作用上来说,使用全类名配置是最简单的,也是比较常用的,是没有特定用处的bean的常用配置方法,但是对于一些高级的用法,譬如使用FactoryBean获取某个对象的动态代理对象,应用有:AOP什么的,总而言之,FactoryBean的能力要强于普通的全类名配置,另外要注意的是:全类名配置虽然功能不如FactoryBean,但是定义和应用上要简便于FactoryBean
*使用注解的方式
*目前在实际开发中,基于注解配置bean的方式还是比较流行的
*首先要声明自动扫描,使用<context:component-scan>节点:base package属性用于指定需要扫描的基类包,那这个包里的所有类都会被扫描,当需要扫描多个包时,可以使用逗号隔开。如果进需要扫描特定的类,而不是基包下所有的类,可以使用<resource-pattern>属性来过滤指定的类,另外,<context:include-filter>和<context:
exclude-filter>这两个子节点分别
用于表示要包含的目标类和要排除在外的目标类,通常情况下呢,有多种方式可以进行过滤,譬如说使用注解类型过滤,那这两个子节点的type属性就是annotation,expression属性的值是注解类型的全类名(使用类名或者接口明进行过滤的话,使用的也是类名或者接口名的全限定名),使用include的时候,注意要把默认的Filter设置为FALSE,否则呢,没有任何效果
*基于注解配置bean
1.首先要在XML中配置好,使用自动扫描的节点,因为Spring默认是不使用注解配置的
2.编写bean,只是如果使用注解装装配的话,需要使用响应的注解,对于不想使用Spring默认注解bean的命名方式的话可以使用注解的value属性来自定义bean的id,具体形式为:譬如你使用了component,那么可以这么写:@Component("**")或者@Component(value="")
*基于注解配置bean的属性(更确切来说,是用来配置bean之间的引用关系的)
*配置属性
1.对于配置类的属性,无论该属性是PUblic还是private,只要是添加了@Autowired注解,就会自动注解,注解的方式是采用类型兼容的方式,就是从IoC容器中找和这个属性的类型匹配的bean,然后注解进来,但是,很明显,这样极有可能会造成歧义,因为同一类型很有可能有多个bean,那对于这种情况怎么办呢?
于是乎,就有了两种解决方法,一种呢,是找和参数一样的名称的bean,另外一种呢,就是自己在@Autowired下面再写一个@Qualifier(""),这个里面要写的不是bean的id,二是直接是bean的simpleName,注解的地方可以加到两个地方,一个是@Autowired下面(属性声明的上面或者方法定义的上面),一个是直接写在入参的前面(这种方式在整合Struts2之后很常用)
2.对于所有使用@Autowired注解的属性和方法,都必须实现设置好,否则如果找不到和注解相对应的bean,就会抛出异常,但是,如果我就是这样,这个被注解的属性呢?可以有也可以没有,并不是强制的,那么使用该注解的required属性,并标记为FALSE, 就OK了(解释一下:因为程序运行的时候各个组件是耦合在一起的,所以在程序一开始运行的时候,各个组件什么的只要是)
(配置好的,什么意思呢?就是该注入的在程序一开始的时候就已经注入了,所以,如果使用注解的地方并没有可以注入的bean,肯定报错呀)
*配置方法入参
1.OK,配置方式和配置类的属性方式完全一样
*@Autowired还可以注解数组和集合属性上,对于数据和List,所有匹配到的类型兼容的bean都会被装载进来,对于Map类型,如果键类型为String,那么对于所有和值类型匹配到的bean都会被注入进来,value呢就是bean本身,key就是bean的id
*获取Spring IoC容器(bean容器)的方式?
*使用BeanFactory
*使用ApplicationContext(是BeanFactory的子接口,提供了很多高级特性)
*BeanFactory是Spring的底层基础设施,面向Spring本身,而ApplicationContext则是面向Spring框架的使用者,几乎所有的应用场合都是使用ApplicationContext,而非底层的BeanFactory
*无论使用哪种方式获取bean容器,XML的配置文件是相同的
*ApplicationContext有两个主要的实现类:一个是从类路径下加载XML(ClassPathXmlApplicationContext),一个是从文件系统加载XML(FileSystemXmlApplicationContext)
*ApplicationContext在初始化上下文的时候就已经实例好了所有单例的bean,OK,什么意思呢?对于使用默认作用域(单例)的bean,是这样的,实例化IoC容器的时候就创建好了一个单例bean,每次获取都返回这一个单例bean,而对于不是使用默认作用的bean,例如使用了原型作用域,那在实例化IoC容器的时候并不会实例化bean,一个是没必要,二是,每次获取bean都是要现创建呀
这个是在获取bean上的区别,既然称作作用域,那就有作用域的效果,除了单例,原型,还有Request和Session作用域,分别对应不同的域作用域
*WebApplicationContext是专门为WEB应用而准备的,它允许从相对于WEB根目录的路径中完成初始化工作
*包含其他属性文件?
*Spring提供了一个PropertyPlaceholderConfigurer的BeanFactory后置处理器,这个处理器允许用户把bean配置的部分内容外移到属性文件里,可以在bean配置文件中使用形式为${var}的变量,那这个PropertyPlaceholderConfigurer会从属性文件中加载属性,并且使用这些属性来替换变量
*具体实现方式:首先导入Context命名空间,然后使用这个命名空间里的property-placeholder节点和这个借点的location来配置属性文件的位置:通常将配置文件放到类路径下,然后location属性的值为『classpath:属性文件名』
*譬如要配置一个数据源,使用c3p0吧,需要配置用户名,密码,驱动,URL等这些信息,但是呢,如果直接把数据源的配置放到Spring配置文件中的话,难免会有一些问题,所以通常是单独拿出来配置,然后引用该配置:通常就是写一个.properties文件,然后在Spring配置文件中用到该某一属性时就直接使用『"${var(这里的var是属性文件中的var)}"』代替property相应的Value值即可
*SpEL(Spring Expression Language)Spring表达式语言?
*SpEL是一个支持运行时检查和操作对象图的强大的表达式语言
*SpEL使用#{..}作为界定符,所有在大括号内的字符都被认为是SpEL
*SpEL为bean属性的动态赋值提供了便利
*所有SpEL的接受者都是value值,因为SpEL本身就是一个字符串,然后因为该字符串是一个EL表达式,所以后来再解释就是后来的事情了
*通过SpEL可以实现的功能:
*通过bean的id实现对bean的引用
1.不实用SpEL的话,使用的是ref来应用bean
2.使用SpEL的话,使用Value即可,然后value值呢是一个SpEL表达式,具体为value="#{id}"
*可以通过对bean的引用实现对该bean方法的调用以及引用对象中的属性
1.这个是经常用到的
2.同上一点的2,使用某一个bean的属性或方法,直接使用.调用即可,是动态获取的,所谓动态获取,就是被获取属性bean的属性和方法当前是什么就是什么,动态的嘛
3.也可以调用静态方法
*计算表达式的值,可以直接使用字面值,但是如果赋值一些字面值的话,使用SpEL反而更麻烦了,如果使用SpEL设置字符串的字面值的话,需要使用双引号或者单引号阔起来,支持常见的运算符,也支持加法字符串连接符,三元运算符
*正则表达式的匹配
* 如何实现Bean的后置处理器?
*与其叫后置处理器,不如叫后置过滤器
*编写自己的bean后置处理器
*实现BeanPostProcessor接口
*实现它的两个抽象方法
*然后就把这个后置处理器以配置普通bean的方式配置到XML中就行,而且可以不用配置id,什么意思呢?所有的bean都共用这一个后置处理器,再者详细一点,配置在XML中的bean都要被这个后置处理器过滤,更神奇的是,这个后置处理器功能强大,可以偷梁换柱,什么意思呢?譬如:有一个Person类对象走进这个过滤器了,但是在这两个方法中走出的是一个Animal类对象
*既然所有的bean走的是同一个后置处理器,那么后置处理器只能有一个么?(弱智么?这两个问题有关联么)当然可以有多个!
*泛型依赖注入?
*首先要理解到这里的泛型依赖注入更全面的将是相同泛型参数类型的依赖的自动注入
*根据泛型依赖注入的定义,首先定义好泛型接口,然后在接口层面就定义好了接口间的依赖关系,使用什么依赖注入方式的话也要在接口层面指明,因为会继承下来
*然后就是编写接口的实现类了,编写好之后,不用指明这些类之间的依赖关系啥的,以为已经继承过来了,只需要配置以下,让IoC容器受理就好,然后,使用相同泛型参数类型的接口子类会自动建立依赖关系,并且进行响应的依赖注入
*如何使用Spring的AOP呢?
*首先导入jar包:除了基本的5个jar包之外,然后导入4个用于AOP的jar包,aopalliance,aspectj.weaver,aop,aspectj
*在Java社区中呢,最流行最完整的AOP是AspectJ框架,虽然Spring有自己的AOP框架模块,但是还是推荐使用AspectJ框架
*在Spring中应用AOP主要有两种方式,一种是使用AspectJ注解,一种是使用基于XML的配置
*就现在的整体发展趋势而言,注解由于其简便性更流行起来
*在Spring中使用AOP,根据AOP的实现原理,很简单,首先,你要有自己的业务代码类,(通常这个这些业务代码类有一个共同的接口)然后有切面(横切关注点模块化之后的类)类,然后就是如何将切面类的通知应用到业务类中,OK,你要做的就这么多。至于底层是怎么实现的,核心是动态代理,其他的就不用管了
*使用AspectJ注解
*首先你得先告诉Spring,你要使用AspectJ注解了,然后你使用的AspectJ注解才能起作用,就好像你使用了Bean的自动装配注解一样,都是得告诉Spring,告诉Spring你使用了AspectJ注解的方式为:使用aop命名空间的aspect-autoproxy节点,作用呢是为匹配到切点连接点所在的类自动创建代理对象
*前置通知是方法执行前。后置通知是方法执行后,无论是否返回,无论是否抛出异常。环绕通知比较叼,环绕通知功能很强大,类似于整个动态代理本身。异常抛出通知是方法执行过程中抛出了异常的通知。
*前/后置通知(使用的是通过方法签名来获取的)
1.首先需要编写好业务类,业务类接口,和切面类
2.把业务类和切面类放到IoC容器中(就是配置以下bean咯),并把切面类注解为切面类@Aspect
3. 为通知(切面中的方法)注解切点,如果是前置通知的话,使用@Before("*execution("*")"),*是方法的全限定名譬如:publicint 类全限定名.方法(不带参数变量的参数列表),注意一点的是,在execution中的参数可以使用*通配符(方法参数的通配符使用的的是..),在AspectJ中,有五种通知,前置,后置,环绕,返回,异常抛出(都是针对方法的)
*若目标类与接口和切面位于同一个包中,则可以省略包名
*匹配方法时,除了匹配到的这个类的方法之外会自动代理,这个类的子类的方法匹配到了也会自动代理
4.如果想要获取目标方法的一些信息,或者说是和切点匹配的连接点的信息,需要为通知方法加入一个JoinPoint类型的参数,通过这个参数就可以获得连接点的所有信息咯,譬如目标方法的名称,参数列表等,在Spring中连接点的粒度就是方法级别的,所以放入连接点的的参数,目的就是为了获取目标方法的一些细节
*返回通知和前/后置通知完全一样:但是对于返回通知,还可以多做一点的就是访问到方法的返回值,具体做法是:@AfterReturning这个注解有多个参数,默认的是只有一个参数,那就是切点的描述,但是如果想获取返回值怎么办呢?value用于指定切点,returning用于指定返回值的标志符,这样就可以把返回值获取到了,那怎么使用返回值呢?在通知方法的入参里再加一个参数,
之前不是已经有了一个JoinPoint了么?再加一个Object,这个Object就是返回值,入参的形参标志符是你在@AfterReturnin中指定的return的标志符,然后,你就可以在通知方法中使用返回值了哦
*抛出异常通知和前后置通知一样,但是同样可以访问到发生了什么异常,使用@AfterThrowing的throwing属性就可以获取了,在通知方法的入参中加入一个新参数,类型为Exception(如果不是Exception而是其他的什么特定异常,那么只有在这个特定异常发生之后才会执行异常抛出通知函数,否则不执行),标志符为你指定的异常的标志符,然后在通知方法中就可以访问到异常的相关情况咯
*环绕通知
1.环绕通知需要携带ProceedingJoinPoint类型的参数,这个参数翻译过来就是『正在处理的连接点』,那你甚至可以决定这个目标方法要不要执行,准确来说,这个参数就是目标方法的一个替身
2.环绕通知必须有返回值,而且返回值就是方法执行的返回值本身
3.环绕通知确实很吊,可以在环绕通知里实现前置通知,后置通知,方法正常返回通知,异常抛出通知,对,环绕通知就是这么叼
4.虽然环绕通知很吊,但是老师说实际开发不常用,既然这么叼,为何不用
*对于一个目标方法有多个通知的时候,那这些通知应该以什么样的顺序执行呢?OK,默认怎么执行不管他,你可以自己指定通知的执行顺序,使用@Order注解,括号中的值是int类型的,值越小,优先级越高
*有时候呀,我们就是对一个目标方法书写了很多通知,很显然,在为通知使用方法签名的时候,有多少个通知就需要写多少遍,一点复用性也咩有,那怎么会有复用性呢?OK实现方法如下:
1.定义一个方法,譬如为A(),这个方法是一个完整的方法,有方法体,但是方法体为空
2.为该方法添加注解@PointCut,然后该注解的参数就是方法签名
3.如何实现复用呢?就是以后再使用到方法签名的时候,原本value是要写方法签名的,现在直接写成"A()"就好,仅仅就是简化了书写,但是简化书写不是不写,该写签名的地方还是都要写的
*使用基于XML的配置
*把该配的bean先配置到XML中,再配置什么的话都是后话了
*使用aop命名空间的config节点来配置aop
1.配置切点:使用Pointcut子节点,需要配置expression属性和id属性,OK,expression属性是用来写方法签名的,id是后面用这个切点的引用
2.配置切面和通知:使用Aspect子节点,节点的ref属性指明切面,order指明通知的优先级;然后接下来是在这个节点下配置子节点,使用Before子节点配置前置通知,该子节点需要配置method属性,指明通知方法,只要方法名,因为切面已经指定了,然后配置pointcut属性,指明切点,这就完啦,同样的,配置返回通知和异常抛出通知时,
同样需要配置returning和throwing如果需要的话,配置环绕通知和配置前后置通知一样,都是指明一下通知i方法和切点
*Spring JDBC的使用方式?
*通常情况下呢,我们使用数据库就是每次使用的时候都要连一下,这样就有一个问题呀,首先如果访问的用户多了,那练的就多了,连的多了首先会占带宽,其次可能会让数据库吃不消
*所以,通常情况下使用的是数据库连接池的方式,这样可以避免上述的两个缺点:一是,避免了连接数量过多的问题,因为数据库连接池中连接的数量是在连接池生成的时候就定义好的;二是,提高了数据库访问的效率,因为按照之前的方式来做,每次新的用户访问数据库都需要新连接,使用连接池之后,使用连接好的数据库,不用再重新连接,访问速率提高不少哦
*在Spring中如何实现数据库连接池呢?(配置数据源)
*其实使用c3p0实现数据库连接池,并不是Spring独有的,而是要以一种Spring风格来使用c3p0数据库连接池
1.拷贝jar包,c3p0项目的lib下总共有3个jar包,除了Oracle专用的那个之外,拷贝剩下的两个jar包到项目路径下
2.使用外置属性文件的方式来配置c3p0,把外置文件放到类路径下,然后在XML中配置好property-placeholer
3.配置c3p0数据库连接池类,CombolPooledDataSource,通过property子节点来为这个类注入属性,属性使用的是外置属性
4.然后在使用到的地方,获取上下文容器,从容器中获取数据源(连接池),从连接池获取连接,然后操作数据库
(上面是配置了如何在Spring中使用c3p0数据库连接池)
*那如何使用Spring的JDBC Template模板呢?
*首先配置JDBC Template的bean配置,只需一个入参使用property入参即可:配置一个dataSource
*然后获取JDBC Template类的对象(从IoC容器中获取)
*接下来就是方法的封装:
1.如果想要进行更新操作,jdbcTemplate可选的更新有单条更新(插入,更改,删除)和批量更新(插入,更改,删除),直接在你的方法中对jdbcTemplate类的方法进行调用即可
2.如果想要进行查询操作,同分为单条查询和多条查询,注意对整条记录的查询使用的是带RowMapper参数的查询方法,所谓RowMapper,就是指定一个查询结果和一个类中属性如何进行匹配的行匹配器,什么意思呢?其实一行记录可以匹配多个对象出来,也可以进行全匹配,只匹配出一个对象出来,这取决于你传入的行匹配器,另外,查询结果和属性的匹配也是通过匹配器入参类的setter方法实现的,
也就是说,查询结果的列名称必须有对应的属性名称,否则比配不成,那这时就可以使用查询结果的别名来直接指定查询结果的列名称就行了,另外,RowMapper是一个接口,其常见的实现类是BeanPropertyRowMapper,这个实现类的构造器入参是接收查询结果的类的class,那这是单条查询(使用的是(QueryForObject)),注意一点的是:Spring
JDBC Template不支持级联属性的映射!
因为JDBC Template底层直接就只是JDBC而不是一个ORM框架,不支持级联属性的映射;对于多条记录查询,使用的是query方法,就叫Query方法,不是什么QueryforList什么的,就叫Query方法,也是传入了一个RowMapper,返回一个list,多条记录查询的RowMapper和单条记录查询的RowMapper一样,那这是多条记录查询,如何进行属性查询或者是统计查询呢?使用的还是QueryforObject
不过,由于只是获取单个属性,没有必要使用行匹配器,所以入参就没有RowMapper咯,而就是String的查询语句,返回结果的类类型,和查询参数
*还有一种使用JDBC Template的方式是:继承JDBCDaoSupport,并且注入一个JDBC Template(由于注入方法是final的,所以不能在这个子类中使用自动装配呃方式进行装配,而只能使用XML装配的方式,当然也可以采用方法封装的方式进行自动装配),这样直接使用getJdbcTemplate()获取JDBC Template,然后剩下的操作就都一样了,不过不建议使用这个,这个和直接从IoC容器中获取JDBC
Template
有什么区别么?有,就是与Spring的API发生了耦合,说到底,不建议使用
*在JDBC中使用具名参数(named parameter)?
1.在经典的JDBC用法中,SQL参数是使用占位符?表示,并且受到位置的限制,定位参数的问题在于,一旦参数的顺序发生变化,参数就要重新绑定
2.具名参数:SQL按名称(以冒号开头)而不是按位置进行指定,具名参数更容易维护,可读性更强,具名参数在框架类运行时用占位符取代
3.具名参数只在NameParameterJdbcTemplate中得到支持,注意:该类没有无惨的构造器,要么传入一个JdbcTemplate,要么传入一个dataSource,通常呢是传入一个JdbcTemplate
4.如何使用呢?
*更新操作
1.单条记录更新
*把之前用的问号变了,变成(:变量名)
*创建一个Map,这个map里面的键值对:键是Sql语句中的变量名,值是值
*调用NameParameterJdbcTemplate的响应update方法,传入SQL和map
5.那问题来了,仔细一看,换成NameParameterJdbcTemplate,使用方式上更麻烦了,好处是什么呢?好处就是可以为SQL的入参起名字,这就OK了,因为NameParameterJdbcTemplate设计的目的就是为了使用具名参数的,既然已经知道这个问题了,那能不能解决一下呢?
*我们使用JDBC Template进行查询的时候,是对查询结果进行了行映射的,那能不能在更新的时候也直接传一个bean进去呢,而不是传一个Map进去,当然是OK的
*同样使用NameParameterJdbcTemplate的update方法,传入sql语句和paramSource,这个paramSource是一个SqlParameterSource类型的变量,而SqlParameterSource是一个接口,常用实现类为BeanPropertyParameterSource,该子类有一个带参构造器,直接把设置好属性的bean传进这个构造器就行
*那怎么进行匹配的呢?就是如何把传入的bean和SQL的参数匹配上呢?这就要求SQL参数是具名参数,并且名称和传入bean的对应属性名称一致
*显然,这种直接传bean的方式更适用于实际开发
*Spring的声明式事务管理?
*Spring从不同的事务管理API中抽象了一整套的事务机制,什么是不同的事务管理API呢?你看哈,使用不同的ORM框架,都有起各自的事务管理方式,另外单独使用jdbc又是一种事务管理机制,那不同的事务管理机制API是没法进行统一事务管理的,诺,这个Spring的事务管理API就是对这些个不同事务管理的API进行了封装,开发人员不必了解底层事务的API,就可以利用这些事务机制,有了这些事务机制,事务
管理代码就能独立于特定的事务技术了
*Spring的核心事务管理器抽象是PlatformTransactionManager,这个接口呢封装了一组独立于特定技术的方法,无论是使用Spring的哪种管理策略(编程式or声明式),事务管理器都是必须的
*上述接口PlatformTransactionManager有很多子类,分别对应不同平台的事务管理,譬如:jdbc对应DataSourceTransactionManager,JTA对应JtaTransactionManager,Hibernate对应HibernateTransactionManager,这些实际的事务管理器以普通bean的方式配置在IoC容器中进行使用即可
*发现一个问题呀,MySQL在建表的时候可以加检查异常,但是呢,加了没什么用诶,因为并不支持约束检查
*通常呢,对数据库的操作有不同的层次:DAO接口层、DAO实现层、应用层(服务层)
DAO接口层:定义了都有哪些数据库操作
DAO实现层:实现了接口层中的操作
应用层(服务层):调用实现层的方法,完成业务逻辑(需求)
*Spring的声明式事务如何使用呢?(通常情况下,如果能使用注解就不实用XML了,毕竟注解比较简单,而且注解可以进行编译时检查)
*使用注解的方式
1.首先需要配一个事务管理器,在XML中使用平常配置bean的方式就OK。常见的事务管理器有上面的那几个,不同的事务管理器传入不同的参数,譬如:DataSourceTransactionManager传入的参数为dataSource,然后就醒了
2.然后呢,在XML中加入tx明明空间,并且使用该命名空间下的annotation-driven节点的Transaction-Manager属性配置事务管理器(注意:使用任何注解都要在Spring的XML中进行启用)
3.最后,在响应的应用层(服务层)的响应方法上加上注解@Transational,即可
*Spring的声明式事务细节地方?(比较重要)
1.事务传播性(propagation):常用的有required和required-new,默认的是required,当使用required-new的时候,启动新事务之前会挂起当前事务,新事务执行完了,当前事务接着走。除了这两个常用的取值之外,还有其他的几个取值,只是不太常用,无论是哪个取值,都是Propagation类的属性,不是自己写的一个字符串值
2.事务隔离性(isolation):常用的有读提交,读未提交,可冲复读等等,根据实际情况进行选择使用就好
3.异常回滚性(roll back):对哪些异常进行回滚,对哪些异常不进行回滚,默认情况下对所有运行时异常进行回滚(也咩法对编译时异常进行回滚),这里的异常可以是官方API中的异常,当然也可以是自定义的运行时异常,无论是规定要回滚还是不要回滚的异常,属性的值都是一个数组,通常情况下取默认值即可
4.只读性(read only):用来声明这个事务是否是只读的,如果点名了是只读的,那么数据库引擎就可以对这个事务进行优化,建议事务只读的时候,明确说明
5.事务超时配置(timeout):设置事务在强制回滚之前可以占用的时间,什么意思呢?就是这个事务无论完成,到了超时时间点后,强制回滚,即类似于事务执行的时间片,单位是秒/s
*使用XML配置的方式
1.首先需要配一个事务管理器,在XML中使用平常配置bean的方式就OK。常见的事务管理器有上面的那几个,不同的事务管理器传入不同的参数,譬如:DataSourceTransactionManager传入的参数为dataSource,然后就行
2.然后在XML中加入tx命名空间,配置该命名空间下的advice节点,配置id属性和事务管理器,OK,其实这是在配置通知,所谓通知,因为Spring的事务管理是通过AOP框架来的,接下来是配置属性(tx:attribute)子节点,然后在属性子节点中配置方法节点(tx:method),配置属性子节点,是为了设置事务的属性,那对于不同的方法可能需要不同的
事务属性,接下来就是配置对需要配置的方法的事务属性,对于使用默认事务属性的不用管这一部分,对于需要特别配置属性的使用method子节点,配置method的name(方法名,直接方法名,不用全限定名,那发生冲突怎么办呢?)和相关属性即可,attributes节点可以有多个method节点,method的name属性支持通配符
3.配置事务切点,以及把事务属性和事务切点关联起来:事务切点配置在应用层(服务层)类的方法上,然后配置通知,这里使用的是第二种在Spring使用XML配置AOP的方式
(插一句:在Spring中使用XML配置AOP有两种方式,一种是配置切面,然后在切面中配置各种通知;一种是直接配置通知的应用,之前得先配好通知和切点,然后配置通知时,配置好通知ref和切点ref就好)