Spring学习笔记(3)

Spring学习笔记(3)

前言

今天主要来说一下基于aspectj注解的aop操作,spring的jdbcTemplate操作,c3p0连接池还有事务管理,spring的学习已经接近尾声了

基于aspectj的注解aop操作

在这里我们还是使用book类中的方法来增强mybook类

第一步,在配置文件中先创建对象

<!--创建对象-->
    <bean id="book" class="cn.lcx.aop.Book"></bean>
    <bean id="mybook" class="cn.lcx.aop.MyBook"></bean>

第二步,在spring的核心配置文件中,开启aop操作

<!--开启aop操作-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

第三步,在所要增强的类上面使用注解来完成AOP操作

@Aspect
public class MyBook {
    //在方法上面使用注解完成增强配置
    @Before(value = "execution(* cn.lcx.aop.Book.*(..))")
    public void before1()
    {
        System.out.println("before....");
    }
}

Spring的jdbcTemplate操作

Spring的框架是一站式框架,在针对javaee的三层结构中,每一层都有解决的技术,在dao层,使用jdbcTemplate,它对jdbc进行了封装,对数据库进行crud操作。

第一步,设置数据库信息

        DriverManagerDataSource dataSource= new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/Spring");
        dataSource.setUsername("root");
        dataSource.setPassword("abc3770166");

第二步,创建jdbcTemplate对象,设置数据源

JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);

第三步,调用方法,来对数据库进行操作,以下为增加,修改,删除完整代码

package cn.lcx.jdbc;

import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

public class JdbcDemo1 {

    //1.添加操作
    @Test
    public void add()
    {
        //设置数据库信息
        DriverManagerDataSource dataSource= new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/Spring");
        dataSource.setUsername("root");
        dataSource.setPassword("abc3770166");
        //创建jdbcTemplate对象,设置数据源
        JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
        //调用方法
        String sql = "insert into user values(?,?)";
        int rows=jdbcTemplate.update(sql,"lucy","250");
        System.out.println(rows);
    }

    @Test
    //2.修改操作
    public void update()
    {
        //设置数据库信息
        DriverManagerDataSource dataSource= new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/Spring");
        dataSource.setUsername("root");
        dataSource.setPassword("abc3770166");
        //创建jdbcTemplate对象,设置数据源
        JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
        //调用方法
        String sql=" update user set password=? where username=?";
       int rows= jdbcTemplate.update(sql,"1314","lucy");
        System.out.println(rows);
    }

    @Test
    //3.删除操作
    public void delete()
    {
        //设置数据库信息
        DriverManagerDataSource dataSource= new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/Spring");
        dataSource.setUsername("root");
        dataSource.setPassword("abc3770166");
        //创建jdbcTemplate对象,设置数据源
        JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
        //调用方法
        String sql="delete from user where username=?";
        int rows= jdbcTemplate.update(sql,"lucy");
        System.out.println(rows);
    }
}

查询方法

查询表中有多少条记录

 @Test
    public void testCount()
    {
        //设置数据库信息
        DriverManagerDataSource dataSource= new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/Spring");
        dataSource.setUsername("root");
        dataSource.setPassword("abc3770166");
        //创建jdbcTemplate对象,设置数据源
        JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
        //调用方法得到记录数
        String sql = "select count(*) from user ";
        int count=jdbcTemplate.queryForObject(sql,Integer.class);
        System.out.println(count);
    }

这里不难理解,queryForObject方法需要两个参数

  • 第一个参数是sql语句
  • 第二个参数是返回类型的class

查询返回对象

我们需要创建一个实体类来保存返回来的数据
sping3-1
从这个方法我们可以看出,第二个参数是Rowmapper,是一个接口


实现这个接口

class MyRowMapper implements RowMapper<User>
{
    @Override
    public User mapRow(ResultSet rs,int num) throws SQLException
    {
        //从结果集里面把数据得到
        String username=rs.getString("username");
        String password=rs.getString("password");
        //把数据封装到对象里面

        User user=new User();
        user.setUsername(username);
        user.setPassword(password);

        return user;
    }
}
//2.查询返回对象
    @Test
    public void testObject()
    {
        //设置数据库信息
        DriverManagerDataSource dataSource= new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/Spring");
        dataSource.setUsername("root");
        dataSource.setPassword("abc3770166");
        //创建jdbcTemplate对象,设置数据源
        JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
        //调用方法得到记录数
        String sql = "select * from user where username=?";
        //第二个参数是接口RowMapper,需要自己写类实现接口,自己做数据的封装
        User user=jdbcTemplate.queryForObject(sql,new MyRowMapper(),"lucy");
        System.out.println(user);
    }

查询返回list集合

//3.返回list集合
    @Test
    public void testList()
    {
        //设置数据库信息
        DriverManagerDataSource dataSource= new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/Spring");
        dataSource.setUsername("root");
        dataSource.setPassword("abc3770166");
        //创建jdbcTemplate对象,设置数据源
        JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
        //调用方法
        String sql ="select * from user";
        List<User>list  =jdbcTemplate.query(sql,new MyRowMapper());
        System.out.println(list);
    }

Spring配置c3p0连接池和dao使用jdbcTemplate

什么是连接池?

连接池用于创建和管理数据库连接的缓冲池技术,缓冲池中的连接可以被任何需要他们的线程使用。当一个线程需要用JDBC对一个数据库操作时,将从池中请求一个连接。当这个连接使用完毕后,将返回到连接池中,等待为其他的线程服务。 连接池的主要优点有以下三个方面。

第一、减少连接创建时间。连接池中的连接是已准备好的、可重复使用的,获取后可以直接访问数据库,因此减少了连接创建的次数和时间。

第二、简化的编程模式。当使用连接池时,每一个单独的线程能够像创建一个自己的JDBC连接一样操作,允许用户直接使用JDBC编程技术。

第三、控制资源的使用。如果不使用连接池,每次访问数据库都需要创建一个连接,这样系统的稳定性受系统连接需求影响很大,很容易产生资源浪费和高负载异常。连接池能够使性能最大化,将资源利用控制在一定的水平之下。连接池能控制池中的连接数量,增强了系统在大量用户应用时的稳定性。

第一步,在配置文件中配置连接池

<!--配置c3p0连接池-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!--注入属性值-->
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/Spring"></property>
        <property name="user" value="root"></property>
        <property name="password" value="abc3770166"></property>
    </bean>

dao使用jdbcTemplate

创建并配置service、dao、jdbcTemplate,在service注入dao,dao注入jdbcTemplate

<bean id="userService" class="cn.lcx.c3p0.UserService">
        <!--注入Dao对象-->
        <property name="userDao" ref="userDao"></property>
    </bean>
    <bean id="userDao" class="cn.lcx.c3p0.UserDao">
        <!--注入jdbcTemplate对象-->
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>
    <!--创建JdbcTemplate对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--传递dataSource-->
    <property name="dataSource" ref="dataSource"></property>

Service类

public class UserService {

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void add()
    {
        userDao.add();
    }
}

dao类

public class UserDao {
    //得到jdbcTemplate对象
    private JdbcTemplate jdbcTemplate;
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    public void add() {
    String sql= "insert into user values(?,?)";
    jdbcTemplate.update(sql,"lcx","520");
    }
}
  • 在这里,我们调用userService里的add方法同时并调用userdao里的add方法来为数据库表user中 插入了lcx,520这两个数据
   public void test()
   {
       ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
       UserService userService=(UserService) context.getBean("userService");
       userService.add();
   }

Spring的事务管理

什么是事务?

事务逻辑上的一组操作,组成这组操作的各个逻辑单元,要么一起成功,要么一起失败

事务特性

  • 原子性:强调事务的不可分割
  • 一致性: 事务的执行的前后数据的完整性保持一致
  • 隔离性: 一个事务执行的过程中,不应该受到其他事务的干扰
  • 持久性: 事务一旦结束,数据就持久到数据库

如果不考虑隔离性引发安全性问题:

  • 脏读:一个事务读到了另一个事务的未提交的数据
  • 不可重复读:一个事务读到了另一个事务已经提交的 update 的数据导致多次查询结果不一致
  • 虚读:一个事务读到了另一个事务已经提交的 insert 的数据导致多次查询结果不一致

Spring事务管理api

事务管理两种方式

编程式事务管理(不用)

声明式事务管理

(1)基于xml配置文件的实现
(2)基于注解的实现

以转账为例来测试Spring的事务管理

  • 首先搭建环境,我们创建一个数据库的表,添加数据
    sping3-2
  • service层又叫业务逻辑层
  • dao层,单纯对数据库操作层,在dao层不添加业务
  • 需求:lcx转账1000给mike,结果 lcx 减少1000 mike 增加1000

Service类

public class OrdersService {
    
    private OrdersDao ordersDao;
    public void setOrdersDao(OrdersDao ordersDao) {
        this.ordersDao = ordersDao;
    }
    //调用dao的方法
    //业务逻辑层,写转账业务
    public void  accountMoney()
    {
        //少1000
        ordersDao.lessMoney();
        //这里会出现异常
        int i= 10/0;
        //多1000
        ordersDao.moreMoney();
    }
}

Dao类

public class OrdersDao {
    //注入jdbcTemplate
    private JdbcTemplate jdbcTemplate;
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
 //dao处理数据库的操作,不写业务操作
    //少钱的方法
    public void lessMoney()
    {
        String sql="update account set salary=salary-? where username=?";
        jdbcTemplate.update(sql,1000,"lcx");
    }
    //多钱的方法
    public void moreMoney()
    {
        String sql="update account set salary=salary+? where username=?";
        jdbcTemplate.update(sql,1000,"mike");
    }
}
  • 以上方法中,lcx少了1000方法执行后出现了异常,mike并没有增加1000,钱消失了。

异常的解决

添加事务管理,出现异常回滚

xml配置

第一步,配置事务管理器

<!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

第二步,配置事务增强

<!--配置事务增强-->
    <tx:advice id="txadvice" transaction-manager="transactionManager">
        <!--做事务操作-->
        <tx:attributes>
            <!--设置方法匹配规则,在这里匹配所有以account开头的方法-->
            <tx:method name="account*"/>
        </tx:attributes>
    </tx:advice>

第三步,配置切面

<!--配置切面-->
    <aop:config>
        <!--切入点-->
        <aop:pointcut id="pointcut1" expression="execution(* cn.lcx.service.OrdersService.*(..))"></aop:pointcut>
       <!--切面-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pointcut1"/>
    </aop:config>

注解配置

配置文件配置如下:

<!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入dataSource-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--开启事务注解-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

在要使用的事务的方法所在类上添加注解

@Transactional
public class OrdersService {