Spring学习笔记

本文详细介绍了Spring框架的核心模块IOC(控制反转)容器,包括XML配置、注解配置以及Bean的作用域。接着讲解了AOP(面向切面编程)的概念和实现方式,包括使用注解实现切面。最后,阐述了Spring与MyBatis的整合,包括数据源配置、事务管理以及操作数据库的示例。内容深入浅出,适合初学者和进阶者了解Spring框架的关键特性。
摘要由CSDN通过智能技术生成

        Spring框架是由软件开发的复杂性而创建的,该框架由一个叫Rod Johnson的程序员在 2002 年最早提出并随后创建。---百度百科

        Spring框架由以下的模块构成,一一进行学习。

        1、IOC容器

         1.1  之前Java代码的学习中,创建对象常常通过new构造器的方式实现。随着业务不断的复杂,代码量不断增加,有时候new的方式不太方便。这时候,可以使用Spring中IOC容器进行实例化对象。

         图解:你所要创建的实体类对象,通通放进Spring容器中,它为你进行保管;在读取一些配置,你就可以从Spring容器中使用这些对象,而不用通过手动new的方式创建。

       1.2.1  基于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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="..." class="...">  
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <bean id="..." class="...">
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions go here -->

</beans>


        

       1.2.2 如何通过这种方法进行对象的创建?

1.创建实体类Hello。

public class Hello {
    private String str;

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }
}

注意:务必对属性添加set方法,这是依赖注入的关键!

2.通过xml文件配置IOC容器(beans.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
        <!--使用spring来创建对象,对象都称作Bean
        以前使用new的方式来创建对象
        对象类型 对象名 = new对象类型()
        Hello hello = new Hello()

        使用spring后:
        id:对象名
        class:对象类型的全路径
        property:给对象的属性设置值
        -->
        <bean id="hello" class="com.leo.pojo.Hello">
            <property name="str" value="Spring"></property>
        </bean>
</beans>

        这样,一个id为"hello"的对象就已经存在于该IOC容器中,随时准备调用。

        如果想在该IOC容器中同时生成多个待用对象,重复此代码即可(id不可重复):

<bean id="id名" class="com.leo.pojo.Hello"> <property name="str" value="Spring"></property> </bean>

        1.2.3 如何获取(调用)该容器中的对象?

ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        使用此代码能够获取该IOC容器,括号内就填上你所配置好的xml文件名。一旦获取了IOC容器,所有在xml文件中存在的bean(对象)都会生成,等待调用。

Hello hello= context.getBean("hello");

        通过此代码,你就获得了你在xml文件中生成的id为"hello"的对象,并可以进行使用,与new方法创建的对象一致。

完整代码:

public class MyTest {
    public static void main(String[] args) {
        //获取Spring的上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //我们的对象(bean)都在Spring中管理,要使用时从里面取出来即可
        Hello hello = (Hello) context.getBean("hello");
        System.out.println(hello.toString());
    }
}

结果:

        1.3 生成bean并给属性赋值的方式

1.3.1:通过有参构造器注入。

实体类:

public class User {
    private String name;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }

    public User(String name) {
        this.name=name;
    }

    public String getName() {

        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void show(){
        System.out.println("name=" + name);
    }
}

此类中存在有参(name)构造器。对于有参构造器形式的注入,xml中有3方式。

xml:

<!--有参构造器的3种实现方式-->
<!--方式1:通过下标赋值-->
<!--<bean id="user" class="com.leo.pojo.User">-->
    <!--<constructor-arg index="0" value="leo"/>-->
<!--</bean>-->

<!--方式2:通过类型赋值 不推荐-->
<!--<bean id="user" class="com.leo.pojo.User">-->
    <!--<constructor-arg type="java.lang.String" value="leooo"/>-->
<!--</bean>-->

<!--方式3:通过参数名称赋值  推荐使用-->
<bean id="user" class="com.leo.pojo.User">
    <constructor-arg name="name" value="乐子"/>
</bean>

        通过<constructor/>标签来实现构造器注入值的方式如上。

方式1:通过下标(类似于数组下标)。若存在构造器public Xxx(String name,int age,float salary...),则index=0则给name属性赋值,index=1给age属性赋值...

方式2:通过类型赋值(不推荐)。public Xxx(String name,int age,float salary...),通过type="java.lang.String"给name属性赋值,type="int"给age属性赋值...但是,如果构造器中存在同一种类型的多个参数,那么此方法就会失效。

方式3:通过参数名称赋值(推荐使用)。public Xxx(String name,int age,float salary...)中,<constructor-arg name="name" value="乐子"/>,name=你所要赋值的属性,value则为你所想赋的值。使用此方法比较清晰,很容易将属性名与值对应。<constructor-arg name="age" value="13"/>则给age属性赋了值。

1.3.2:通过set注入。

通过set注入的前提是为该属性提供set方法。通过set方式注入,往往能注入一些复杂类型的属性,或者是注入多元素的属性(集合、数组...)时更加方便。

实体类(Student)

public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbies;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private Properties info;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", address=" + address +
                ", books=" + Arrays.toString(books) +
                ", hobbies=" + hobbies +
                ", card=" + card +
                ", games=" + games +
                ", wife='" + wife + '\'' +
                ", info=" + info +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String[] getBooks() {
        return books;
    }

    public void setBooks(String[] books) {
        this.books = books;
    }

    public List<String> getHobbies() {
        return hobbies;
    }

    public void setHobbies(List<String> hobbies) {
        this.hobbies = hobbies;
    }

    public Map<String, String> getCard() {
        return card;
    }

    public void setCard(Map<String, String> card) {
        this.card = card;
    }

    public Set<String> getGames() {
        return games;
    }

    public void setGames(Set<String> games) {
        this.games = games;
    }

    public String getWife() {
        return wife;
    }

    public void setWife(String wife) {
        this.wife = wife;
    }

    public Properties getInfo() {
        return info;
    }

    public void setInfo(Properties info) {
        this.info = info;
    }
}

该类中存在着基本类型的属性name,非基本类型address,以及集合类型等属性。接下来探究如何通过set注入的方式给他们赋值。

public class Address {
    private String address;

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

1.3.2.1:注入普通类型的值:


        普通类型的值只需要在bean标签中用name-value注入。

<!--注入普通值 value-->
        <property name="name" value="关公"/>

1.3.2.2:注入非普通类型的值(注入对象):

        注入对象通过name-ref注入,前提是已经存在了一个待注入的bean。

<!--创建bean-->
    <bean id="address" class="com.leo.pojo.Address">
        <property name="address" value="海垦路"/>
    </bean>
<!--注入bean ref-->
        <property name="address" ref="address"/>

1.3.2.3:注入数组:

        property中提供了<array/>这一标签以供数组注入。

<!--注入数组-->
        <property name="books">
            <array>
                <value>红楼梦</value>
                <value>三国演义</value>
                <value>水浒传</value>
                <value>西游记</value>
            </array>
        </property>

1.3.2.4:注入List集合

        <list/>标签注入即可。

<!--注入list-->
        <property name="hobbies">
            <list>
                <value>吹牛逼</value>
                <value>健身</value>
                <value>打游戏</value>
            </list>
        </property>

1.3.2.5:注入Map

        <map/>标签,采用的是entry key-value方式注入了键值对

<!--注入map-->
        <property name="card">
            <map>
                <entry key="学号" value="20010100"/>
                <entry key="身份证" value="19010100103"/>
            </map>
        </property>

1.3.2.6:注入Set

        <set/>标签

<!--注入set-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>2K</value>
                <value>FIFA</value>
            </set>
        </property>

1.3.2.7:注入null

        

<!--注入null-->
        <property name="wife">
                <null/>
        </property>

注意:注入null,必须是通过<null/>标签,若是value=""注入的则是空字段(非null)

1.3.2.8:注入propertie:

<!--注入properties-->
        <property name="info">
            <props>
                <prop key="性别">男性</prop>
                <prop key="年龄">22</prop>
            </props>
        </property>

注意与注入map的区别。

        1.3.3:利用p和c命名空间注入属性。

p(properties)和c(constructor)命名空间注入属性来简化上述两种方式注入属性。如果想使用,首先在xml文件的顶部添加如下两行

xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
<?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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--p命名空间,通过set方法注入-->
    <bean id="user" class="com.leo.pojo.User" p:name="张亮" p:age="13" scope="prototype"/>

    <!--c命名空间,通过构造器注入-->
    <bean id="user2" class="com.leo.pojo.User" c:age="22" c:name="王大厨"/>

当引入p和c命名空间之后,bean字段中会出现p:和c: ,填入相关属性即可。

1.4. bean的作用域。

        在上面的p命名空间注入属性后,可以看见后面有scope这么一个属性。scope,就是该bean的作用域,存在着4个值,分别是:singleton(默认),prototype,request,session。其中后两个是针对于web应用中的,这里就介绍前2个singleton和prototype。

        singleton:如果把一个bean的作用域设置成这个,那么每次从IOC容器中获取的这个bean都是同一个对象。换而言之spring只会产生一个该对象。

        prototype:每次从IOC容器中获取这个bean,都会返回不同的对象。就是说spring会在每次获取时都产生新的实例。

1.5 autowired自动注入

        定义3个实体类如下:

public class Cat {
    public void shout(){
        System.out.println("miao!");
    }
}
public class Dog {
    public void shout(){
        System.out.println("wang!");
    }
}
public class People {

    private Dog dog;
    private Cat cat;
    private String name;

    @Override
    public String toString() {
        return "People{" +
                "dog=" + dog +
                ", cat=" + cat +
                ", name='" + name + '\'' +
                '}';
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

        people类中存在着Cat和Dog类型的属性。我们给属性全部设置set方法,以便后续注入值。

根据之前所学的知识,若想给dog和cat属性都注入值,需要通过property-ref的方式:

<bean id="cat" class="com.leo.pojo.Cat"/>
<bean id="dog" class="com.leo.pojo.Dog"/>

<bean id="people" class="com.leo.pojo.People">
        <property name="name" value="中国"/>
        <property name="dog" ref="dog"/>
        <property name="cat" ref="cat"/>
    </bean>

        然而,在有了自动注入之后,对于dog和cat属性,我们可以省略手动的注入值,由spring帮我们自动的注入。spring提供了2中自动注入的方式:byType和byName。

        byType:根据类型。spring会根据该属性的类型,自动寻找IOC容器中存在且符合该类型的bean(相同class),将其自动注入:

<bean id="cat" class="com.leo.pojo.Cat"/>
<bean id="dog" class="com.leo.pojo.Dog"/>

<bean id="people" class="com.leo.pojo.People" autowire="byType">
        <property name="name" value="中国"/>
    </bean>

        byName:根据名称。spring自动的在IOC容器中寻找和实体类中属性名一致的bean id的bean来自动注入:

 <bean id="cat" class="com.leo.pojo.Cat"/>
 <bean id="dog" class="com.leo.pojo.Dog"/>
 <bean id="cat2" class="com.leo.pojo.Cat"/>
 <bean id="dog2" class="com.leo.pojo.Dog"/>

<bean id="people" class="com.leo.pojo.People" autowire="byName">
        <property name="name" value="hiLeo"/>
    </bean>
 

由于People类中属性名为cat和dog,所以注入了前两行的bean。

1.6  使用注解开发

        如果IOC容器中存在大量的bean时,通过在xml文件中添加,代码量极大。使用注解开发可以极大地减少代码量,并让代码看起来更加简单。

        之前的开发中,我们想在IOC容器中注册一个bean,都是通过在xml文件中添加<bean/>标签来实现。通过注解开发又如何实现?

 1.6.1 使用注解开发的准备工作

        

<context:annotation-config/>
<context:component-scan base-package=""/>

将这两行的代码放到你的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
        http://www.springframework.org/schema/context/spring-context.xsd">
    <!--开启注解支持-->
    <context:annotation-config/>
    <!--扫描包下注解-->
    <context:component-scan base-package="com.leo"/>
</beans>

1.6.2 使用注解开发

使用了注解开发后我们以后创建对象就不需要在xml文件中添加,只需要通过注解即可实现。

@Component
@Scope("singleton")
public class User {
    @Value("达伦1")//优先
    public void setName(String name) {
        this.name = name;
    }

    @Value("达伦")//相当于注入了property的value
    public String name;
}

@Component:相当于<bean id=user class="....User">

@Scope:设置该bean的作用域,默认为singleton

@value:放在属性或者set上,给属性注入值。如果两者头上都有此注解,则属性值是被注入set方法上的。

@Controller、@Repository、@Service,作用都和@Component一致,新建对象。只是使用的层不同,分别用在controller、dao、service、pojo层。

1.6.3 使用注解自动注入

使用注解也可以完成自动注入的功能,我们将上面自动注入的例子修改:

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
        http://www.springframework.org/schema/context/spring-context.xsd">

        <!--开启注解-->
    <context:annotation-config/>
    <context:component-scan base-package="com.leo.pojo"/>

</beans>
@Repository//自动创建bean,id为cat
public class Cat {
    public void shout(){
        System.out.println("miao!");
    }
}
@Repository//自动创建id为dog的bean
public class Dog {
    public void shout(){
        System.out.println("wang!");
    }
}
@Repository
public class People {

    @Autowired(required = false)//直接在属性上使用。也可以在set方法上.如果这样显示标注了false,则可以为空
    @Qualifier(value = "dog")//指定的寻找dog并装配
    private Dog dog;
    @Autowired//使用此可以省略set方法,前提是该bean必须在ioc中存在且名字一致
    @Qualifier(value = "cat")
    //@Resource(name="")注解也可以
    private Cat cat;
    private String name;

    @Override
    public String toString() {
        return "People{" +
                "dog=" + dog +
                ", cat=" + cat +
                ", name='" + name + '\'' +
                '}';
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

@Autowired:进行byType自动装备

@Qualifier:用于@Autowired下面,一起使用,用于在存在多个同类型的bean时指定id注入

@Resource(name=""):集成上面2个注解的功能,一个顶俩。

1.7 使用配置类代替xml文件开发

        之前我们都是使用applicationContext.xml文件进行开发,现在我们可以改成使用配置类来代替配置文件。

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");//使用配置文件创建IOC容器
        ApplicationContext context = new AnnotationConfigApplicationContext(Myconfig.class);//使用配置类创建IOC容器

创建IOC容器的方式改变了。

1.7.1 创建配置类的注解

@Configuration:类上标有此注解说明为配置类

@Bean:在方法上添加该注解,作用等同于xml文件中的<bean/>标签

@Bean//生成User实例
    public User getUser(){//id
        return new User();//class
    }

这样就相当于在IOC容器中创建了一个user bean。

1.7.2 使用IOC中的bean

public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(Myconfig.class);//用config类创建IOC容器
        User user = context.getBean("getUser", User.class);//方法名
        System.out.println(user);
    }

                        2.AOP(面向切面编程)

        2.1 在业务中,往往代码已经写死。这时候如果想在其中添加某项功能,直接修改源代码的方式是不合适的,这样会破坏原来的代码。这时候使用aop可以在不修改源代码下添加功能,降低了代码的耦合性。aop的本质是动态代理。

        在实现AOP前必须加入以下依赖aspectj

<dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjtools</artifactId>
            <version>1.9.5</version>
        </dependency>
    </dependencies>

        2.2 实现切面编程

2.2.1 方式1:使用spring接口来实现(推荐)

        spring提供了几个常用的接口实现aop:

MethodInterceptor:环绕advice
MethodBeforeAdvice:before advice
AfterReturningAdvice:after advice

编写接口:

public interface UserService {
    void add();
    void delete();
    void query();
    void update();
}

实现类:

public class UserServiceImpl implements UserService{
    public void add() {
        System.out.println("增加了一个用户");
    }
    public void delete() {
        System.out.println("删除了一个用户");
    }

    public void query() {
        System.out.println("查询了一个用户");
    }
    public void update() {
        System.out.println("修改了一个用户");
    }
}

编写通知(待插入的功能):

MethodBeforeAdvice:简单的前置通知,在待增强的方法前调用

AfterReturningAdvice:后置通知,在待增强方法后调用,存在返回值。

public class Log implements MethodBeforeAdvice {
    //method:需要被代理的方法
    //objects:方法中的参数
    //o:目标对象
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println(method.getClass().getName()+"类的前"+method.getName()+"被执行了");
    }
}
public class AfterLog implements AfterReturningAdvice {
    //o:返回值
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println(method.getClass().getName()+"后执行了"+method.getName()+"方法,结果为:"+o);
    }
}

编写配置类:

<!--方式1:采用spring接口-->
   <!--注册bean-->
   <bean id="userService" class="com.leo.service.UserServiceImpl"/>
   <bean id="log" class="com.leo.log.Log"/>
   <bean id="afterLog" class="com.leo.log.AfterLog"/>

   <!--配置aop-->
   <aop:config>
      <!--切入点pointcut,expression表达式,execution(...):需要执行的位置-->
      <aop:pointcut id="pointcut" expression="execution(* com.leo.service.UserServiceImpl.*(..))"/>
      <!--执行环绕增强 advice-ref:等待加入的类bean;pointcut:需要切入的切入点-->
      <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
      <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
   </aop:config>

测试结果:

2.2.2 使用自定义增强类来实现 

        接口,实现类代码不变,自定义一个增强类:

public class DiyPointcut {
    public void before(){
        System.out.println("方法执行前");
    }
    public void after(){
        System.out.println("方法执行后");
    }
}

xml文件:

<!--方式2:自定义类-->
    <!--注册bean-->
    <bean id="userService" class="com.leo.service.UserServiceImpl"/>
    <bean id="diy" class="com.leo.diy.DiyPointcut"/>

    <aop:config>
        <!--自定义切面 ref:要引用的类-->
        <aop:aspect ref="diy">
          <!--定义切入点-->
          <aop:pointcut id="point" expression="execution(* com.leo.service.UserServiceImpl.*(..))"></aop:pointcut>
          <!--定义通知-->
          <aop:before method="before" pointcut-ref="point"/>
          <aop:after method="after" pointcut-ref="point"/>
      </aop:aspect>
   </aop:config>

结果:

 

2.2.3 使用注解实现

        使用注解时必须在配置文件中开启注解扫描

<aop:aspectj-autoproxy/>

增强类:

@Aspect//标记为一个切面
public class AnnoPiontCut {

    @Before("execution(* com.leo.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("增强之前");
    }
    @After("execution(* com.leo.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("增强之后");
    }

    @Around("execution(* com.leo.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");
        Signature signature = jp.getSignature();//获取签名
        System.out.println(signature);
        jp.proceed();//执行方法
        System.out.println("环绕后");
    }
}

@Before:待增强方法前执行

@After:待增强方法后执行

@Around:环绕待增强方法执行

配置文件:

<!--方式3:使用注解方式-->
   <bean id="annoPiontCut" class="com.leo.diy.AnnoPiontCut"/>
   <bean id="userService" class="com.leo.service.UserServiceImpl"/>
   <!--开启注解扫描-->
   <aop:aspectj-autoproxy/>

结果:

         3.spring-mybatis

spring中整合mybatis,可以完成mybatis的操作。

3.1 导入相关依赖

 <dependencies>
        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.9</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.9</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
            <scope>runtime</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>

        </resources>
    </build>

3.2 实现相关配置

mybatis-config.xml

<?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>

    <typeAliases>
        <package name="com.leo.pojo"/>
    </typeAliases>

</configuration>

这个配置文件可以整合到其他的配置文件中,留下是为了说明使用了mybatis。

spring-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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--Spring注入Datasource数据源替换Mybatis的
    这里使用Spring的JDBC:org.springframework.jdbc.datasource.DriverManagerDataSource
    -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306"/>
        <property name="username" value="root"/>
        <property name="password" value="gzx123456"/>
    </bean>

    <!--sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/leo/Mapper/*.xml"/>
    </bean>

    <!--SqlSessionTemplate:相当于sqlSession 必须使用有参构造注入sqlSessionFactory-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

</beans>

此配置文件可以用作整合mybatis-spring的模板,使用时只需要修改成对应的值即可。

3.3 spring中操作数据库

        3.3.1 方式一:手动创建SqlSessionTemplate

    3.3.1.1 写接口

public interface UserMapper {
    List<User> selectUser();
}

  3.3.1.2 写Mapper对应的xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.leo.Mapper.UserMapper">

    <select id="selectUser" resultType="user">
        select * from mybatis.user;
    </select>
</mapper>

  3.3.1.3 编写接口对应的实现类(与mybatis不同)

public class UserMapperImpl implements UserMapper{

    private SqlSessionTemplate sqlSession;

    //set注入
    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    public List<User> selectUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}

在spring中操作数据库,必须引入SqlSessionTemplate类,此类相当于mybatis中的sqlSession。

实现的方法中,也是通过SqlSessionTemplate类的对象操作

3.3.1.4 新建一个applicationContext.xml, 在IOC容器中注入实现类的对象

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <import resource="spring-dao.xml"/>//引入spring-mybatis模板配置

    <!--注入实现类-->
    <bean id="userMapper" class="com.leo.Mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>
</beans>

这样就可以通过spring操作数据库了。

测试:

@Test
    public void myTest1() throws IOException {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        for (User user : userMapper.selectUser()) {
            System.out.println(user);
        }
    }

结果:

 

        3.3.2 通过继承自动获取SqlSessionTemplate

其他的地方不变,接口实现类改为如下:

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
    public List<User> selectUser() {
//        SqlSession sqlSession = getSqlSession();
//        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//        return mapper.selectUser();
       return getSqlSession().getMapper(UserMapper.class).selectUser();
    }
}

继承了SqlSessionDaoSupport类,可以直接通过getSession方法获取sqlSession来操作数据库。

测试结果相同。

        3.4 spring中操作事务。

3.4.1 在mybatis-spring的模板的xml文件中添加事务声明

<!--配置声明式事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg ref="dataSource" />
    </bean>

    <!--结合aop实现事务的植入-->
    <!--配置事务通知-->
    <tx:advice id="txAdvisor" transaction-manager="transactionManager">
        <!--需要配置事务的方法-->
        <!--propagation:事物的传播性-->
        <tx:attributes>
            <tx:method name="add" propagation="REQUIRED"/>
            <tx:method name="delete" propagation="REQUIRED"/>
            <tx:method name="update" propagation="REQUIRED"/>
            <tx:method name="query" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    
    <!--配置事务切入-->
    <aop:config>
        <aop:pointcut id="txPointCut" expression="execution(* com.leo.Mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvisor" pointcut-ref="txPointCut"/>
    </aop:config>

将这段代码添加到上面的模板中,作为支持事务的最终模板

3.4.2 写接口

public interface UserMapper {
    List<User> selectUser();
    int addUser(User user);
    int deleteUser(int id);
}

3.4.3 写mapper.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.leo.Mapper.UserMapper">

    <select id="selectUser" resultType="user">
        select * from mybatis.user;
    </select>

    <insert id="addUser" parameterType="user">
        insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd});
    </insert>

    <delete id="deleteUser" parameterType="_int">
        deletes from mybatis.user where id=#{id};//这里故意写错了delete,手动制造错误
    </delete>
</mapper>

3.4.3 写实现类

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{

    private User user = new User(12,"王打雷","wwdl");

    public List<User> selectUser() {
        UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
        mapper.addUser(user);
        mapper.deleteUser(11);//这里的deleteUser方法有错误
        return mapper.selectUser();
    }

    public int addUser(User user) {
        return getSqlSession().getMapper(UserMapper.class).addUser(user);
    }

    public int deleteUser(int id) {
        return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
    }
}

 

这里手动的制造了一个错误,按事务的一致性来说,应该一个操作都不执行。

3.4.4 测试后结果:

 报错,sql语法错误。

此时数据库:

 

 确实没有增加新用户。

将语法修改正确后,在执行,按理来说应该增加id为12的用户,删除id为11的。

结果:

测试成功! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值