Spring学习路之初级JDBC模块

以下内容集成到了GitHub项目中,有兴趣的朋友可以看一下GitHub

https://github.com/HeShuai-GitHub/springDemo.git

随手记

权限:read 1,write 2,execute 4

一、spring maven依赖引入

<!--spring依赖 start-->

<!--这个jar文件包含Spring 框架基本的核心工具类。Spring 其它组件要都要使用到这个包里的类,是其它组件的基本核心-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
    <!--    这个jar 文件是所有应用都要用到的,它包含访问配置文件、创建和管理bean 以及进行Inversion ofControl / Dependency Injection(IoC/DI)
        操作相关的所有类。如果应用只需基本的IoC/DI 支持,引入spring-core.jar 及spring-beans.jar 文件就可以了。-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
    <!--    这个jar 文件为Spring 核心提供了大量扩展。可以找到使用Spring ApplicationContext特性时所需的全部类,
        JDNI 所需的全部类,instrumentation组件以及校验Validation 方面的相关类。-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
        <!--支持缓存Cache(ehcache)、JCA、JMX、 邮件服务(Java Mail、COS Mail)、任务计划Scheduling(Timer、Quartz)方面的类。-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
        <!--模块提供了一个强大的表达式语言,用于在运行时查询和处理对象图。该语言支持设置和获取属性值;属性赋值,
        方法调用,访问数组的内容,收集和索引器,逻辑和算术运算,命名变量,并从Spring的IOC容器的名字对象检索,
        它也支持列表选择和投影以及常见的列表聚合。-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>

        <!--spring jdbc依赖,这个jar 文件包含对Spring 对JDBC 数据访问进行封装的所有类。-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
        <!--依赖数据库的jar包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.26</version>
        </dependency>

        <!--AOP引用 start-->
        <!--这个jar 文件包含在应用中使用Spring 的AOP 特性时所需的类和源码级元数据支持。-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.1</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.1</version>
        </dependency>
        <!--提供对AspectJ的支持,以便可以方便的将面向方面的功能集成进IDE中-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>
        <!--AOP引用 end-->

        <!--spring依赖 end-->

二、jdbcTemplate

1.介绍

jdbcTemplate是spring为了更加易于使用JDBC操作数据库而封装的一个抽象层,以此方便对数据库的增删改查
作为spring的核心,jdbcTemplate的设计之初,是为了不同jdbc的操作提供模板方法,通过这种方式,可以在尽可能灵活的情况下,将数据库的存取工作降到最低。
以下将创建一个简单的jdbcTemplate 增删改查的例子,这里为了减少代码冗余,使用了Junit单元测试,对单元测试不了解的朋友可以直接参考BenHeart
的博客

2. 例子

2.1 所涉及到的mysql 数据库表

CREATE TABLE wct_city (id int NOT NULL AUTO_INCREMENT, title varchar(500), ownid varchar(10), sid int, shop varchar(255), PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO wct_city (id, title, ownid, sid, shop) VALUES (1, '秦皇岛', null, null, null);
INSERT INTO wct_city (id, title, ownid, sid, shop) VALUES (2, '石家庄', null, null, null);

2.2 数据库表所对应的modal类

public class CityModal {

    private String id;

    private String title;

    private String sid;

    private String shop;



    @Override
    public String toString() {
        return "CityModal{" +
                "id='" + id + '\'' +
                ", title='" + title + '\'' +
                ", sid='" + sid + '\'' +
                ", shop='" + shop + '\'' +
                '}';
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getSid() {
        return sid;
    }

    public void setSid(String sid) {
        this.sid = sid;
    }

    public String getShop() {
        return shop;
    }

    public void setShop(String shop) {
        this.shop = shop;
    }
}

2.3 junit测试实现类

public class CityDaoTest { 

    private JdbcTemplate jdbcTemplate;

    @Before
    public void before() throws Exception {
        ApplicationContext ap=new ClassPathXmlApplicationContext("jdbc/JDBC-Context.xml");
        jdbcTemplate=ap.getBean("jdbcTemplate",JdbcTemplate.class);
    }

    @After
    public void after() throws Exception {
    }

    /**
     * 测试JdbcTemplate的query查询方法,queryForObject返回值是一个泛型,较适合查询一条语句
     * query 返回类型为list<T>,返回的是一个数组,所以比较适合返回一组数据
     */
    @Test
    public void query(){
        String sql="select id,title,ownid,sid,shop from wct_city ";
        RowMapper<CityModal> rowMapper=new BeanPropertyRowMapper<CityModal>(CityModal.class);
        List<CityModal> list=jdbcTemplate.query(sql,rowMapper);
        for(CityModal city:list){
            System.out.println(city);
        }
        System.out.println("*************************");
        sql="select id,title,ownid,sid,shop from wct_city where id= ?";
        CityModal cityModal=jdbcTemplate.queryForObject(sql,new Object[]{1},rowMapper);
        System.out.println(cityModal);
    }

    /**
     * jdbcTemplate.update方法,可以对数据库做增删改操作
     * jdbcTemplate的编码格式可能和数据库的编码格式出现不一致的情况,
     * 所以需要在数据连接的url后面添加“characterEncoding=utf8”
     * 如:jdbc:mysql://localhost:3306/usrdel?characterEncoding=utf8
     */
    @Test
    public void update(){
        String sql="update wct_city set title= ? where id= ?";
        jdbcTemplate.update(sql,"秦皇岛","1");
    }

    /**
     * jdbcTemplate.update 对数据库进行添加操作
     */
    @Test
    public void insert(){
        String sql="insert wct_city values(null,?,?,?,?)";
        jdbcTemplate.update(sql,"唐山","1","2","3");
    }

    /**
     * jdbcTemplate.update 对数据库进行删除操作
     */
    @Test
    public void delete(){
        String sql="delete from wct_city where title=?";
        jdbcTemplate.update(sql,"唐山");
    }
} 

三、事务管理

1. 事务简介

事务具有四种特性ACID:原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)
,相关的概念,有很多博客都有介绍,在这就不一一赘述了,推荐一个博客,有兴趣的可以看一下,王王王王王景的博客

2. 直接上例子

2.1 数据库表

DROP TABLE test_book;
CREATE TABLE test_book (id int NOT NULL AUTO_INCREMENT, rmb decimal(11,0) DEFAULT '0' COMMENT '书价', count int DEFAULT '0' COMMENT '书的库存', PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO test_book (id, rmb, count) VALUES (1, 30, 10);

DROP TABLE test_user;
CREATE TABLE test_user (id int NOT NULL AUTO_INCREMENT, username varchar(50) COMMENT '用户名', rmb decimal(11,0) DEFAULT '0' COMMENT '账户余额', PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO test_user (id, username, rmb) VALUES (1, '小明', 50);

2.2 Dao层设计

/**
 * book表Dao层接口
 */
public interface BookDao {

    Book query(Integer id);

    void update(Integer id,Integer count);
}

/**
 * User表Dao层接口
 */
public interface UserDao {

    User query(Integer id);

    void update(Integer id,Double rmb);

}

@Repository
public class UserDaoImpl implements UserDao {

    @Autowired
    private JdbcTemplate dao;

    public User query(Integer id) {
        String sql="select id,username as userName,rmb from test_user where id= ?";
        RowMapper<User> row=new BeanPropertyRowMapper(User.class);
        User user=dao.queryForObject(sql,new Object[]{id},row);
        return user;
    }

    public void update(Integer id, Double rmb) {
        User user=this.query(id);
        String sql="update test_user set rmb= ? where id = ?";
        dao.update(sql,user.getRmb()-rmb,id);
    }
}

@Repository
public class BookDaoImpl implements BookDao {

    @Autowired
    private JdbcTemplate dao;

    public Book query(Integer id) {
        String sql="select id,rmb,count from test_book where id= ?";
        RowMapper<Book> row=new BeanPropertyRowMapper(Book.class);
        Book book=dao.queryForObject(sql,new Object[]{id},row);
        return book;
    }

    public void update(Integer id, Integer count) {
        Book book=this.query(id);
        String sql="update test_book set count= ? where id = ?";
        dao.update(sql,book.getCount()-count,id);
    }
}

2.3 service层设计

public interface BuyTwoBooksService {

    void buyTwoBooks();

}
public interface BuyBookService {

    void buyBook();

}

@Service
public class BuyBookServiceImpl implements BuyBookService {
    @Autowired
    private BookDao bookDao;
    @Autowired
    private UserDao userDao;

    /**
     * 购买书籍,若不设置事务处理,会产生什么效果呢,可以将@Transaction注解注释后,看一下效果,会造成
     * book表中的库存含量减少了一本书,而user表中的用户余额因为不足,而导致扣款失败,这样就影响了事务中的一致性
     *
     *@Transactional 标注该方法整体为一个事务,需要满足事务的原子性,该标签底层使用aop的思想,也就是动态代理,
     * 所以在spring ioc容器中管理的实际上是代理类,该注解可以在方法上,可以在类上,如果在类上表示类中所有方法都需要满足事务的一致性
     * @Transactional 的参数介绍
     * propagation: A方法和B方法同时具备事务,A方法调用B方法时,会将A方法的事务传递给B方法,B方法对于事务的处理方式就是事务的传播性(propagation)
     *              Propagation.REQUIRED:默认该值,即当A方法调用B方法时,当A方法具备事务,则B方法不会创建事务,否则B方法创建一个新的事务,在自己的事务中运行(常用)
     *以下不举例A、B两个方法了,传播性就是多个事务之间的交互
     *              Propagation.REQUIRES_NEW:当前的方法必须启动新事物,并在他的事务内运行,如果有事务正在运行,则将它挂起(常用)
     *              Propagation.SUPPORTS:如果有事务正在运行,则当前方法就在事务中运行,否则当前方法不在事务中运行
     *              Propagation.NOT_SUPPORTED:当前方法不应该运行在事务中,如果有运行的事务,则将它挂起
     *              Propagation.MANDATORY:当前的方法必须运行在事务内部,如果没有事务,则抛出异常
     *              Propagation.NEVER:当前的方法不应该运行在事务中,如果有运行的事务,则抛出异常
     *              Propagation.NESTED:如果有运行的事务,当前的方法应该在运行的这个事务的嵌套事务中运行,如果没有,就启动一个新事物,并在自己的事务中运行
     *
     * isolation: 事务的隔离级别,这个就不解释了,网上有太多的介绍,也属于关系型数据库基础
     *              Isolation.DEFAULT:根据数据库的默认级别来进行设置
     *             Isolation.READ_UNCOMMITTED:读未提交
     *             Isolation.READ_COMMITTED:读已提交
     *             Isolation.REPEATABLE_READ:可重复读
     *             Isolation.SERIALIZABLE: 串行化
     * timeout:  设置事务超时时间,当事务超时后强制进行回滚操作
     *
     * readOnly: 指定当前事务中的一系列操作是否为只读,并非强制当前方法中只可以包括读操作
     *             readOnly最主要的作用是通知mysql不加锁,以提高数据库的性能
     *             如果readOnly设置为True,但是当前方法中不只包含读操作,还有写操作,在不加锁的情况下,将造成赃读、不可重复读、幻读等问题(需谨慎使用)
     *
     * rollbackFor||rollbackForClassName||noRollbackFor||noRollbackForClassName:设置事务回滚条件,不设置默认发生任何异常都进行回滚
     *              rollbackFor:只有设置的异常才会回滚
     *              noRollbackFor:设置的异常不进行回滚,其他都进行回滚
     *              rollbackForClassName和noRollbackForClassName:基本上上面一致,不过一个是对象参数,一个是类全限定名参数
     */
    @Transactional(rollbackForClassName = {"Exception"})
    public void buyBook() {
        System.out.println("开始购买书籍");
        Book book=bookDao.query(1);
        System.out.println("书籍价格为:"+book.getRmb()+",书籍库存:"+book.getCount());
        //对编号为1的书籍,购买一本
        bookDao.update(1,1);
        book=bookDao.query(1);
        User user=userDao.query(1);
        System.out.println("购买书籍的人是:"+user.getUserName()+",账户余额:"+user.getRmb());
        if(user.getRmb()<book.getRmb()){
            throw new RuntimeException("用户账户余额不足...\n"+"现在书籍库存是:"+book.getCount()+",账户余额:"+user.getRmb()
            +",\n如果标记了@Transactional,他将在发生异常后发生回滚,数据库数据不变");
        }
        userDao.update(1,book.getRmb());
        user=userDao.query(1);
        System.out.println("购买书籍结束");
        System.out.println("现在书籍库存是:"+book.getCount()+",账户余额:"+user.getRmb());
    }
}

/**
 * @program: springDemo
 * @description: 购买两本书,以此来测试事务的传播性,也就是@Transactional的Propagation属性
 * @author: hs
 * @create: 2020-08-16 20:39
 **/
@Transactional //对该类中的所有方法起作用
@Service
public class BuyTwoBooksServiceImpl implements BuyTwoBooksService {

    @Autowired
    private BuyBookService buyBookService;

    public void buyTwoBooks() {
        System.out.println("购买两本书    开始");
        System.out.println("购买第一本书  开始");
        buyBookService.buyBook();
        System.out.println("购买第一本书  结束");
        System.out.println("***************");
        System.out.println("购买第二本书  开始");
        buyBookService.buyBook();
        System.out.println("购买第二本书  结束");
        System.out.println("购买两本书    结束");
    }
}

以上分别包含了两个dao接口,两个实现,两个service接口,两个实现,代码较多,有兴趣的同学可以查看我的GitHub

2.4 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" 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-4.2.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"
>

    <!--使用Bean定义 来读取properties文件-->
<!--    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:/jdbc/db.properties"></property>
    </bean>-->

    <!--context命名空间  读取资源文件 读取properties文件
        必须先配置context命名空间,xmlns:context="http://www.springframework.org/schema/context"
		 xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"
    -->
    <context:property-placeholder location="jdbc/db.properties"></context:property-placeholder>

    <!--获取连接数据看的数据源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

    <!--将数据源注入到jdbcTemplate中-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--设置事务管理器,成员属性dataSource用来设置数据源-->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--开启事务管理注解方式,transaction-manager用来设置事务管理器-->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>

    <!--扫描指定路径下的包,并开启spring注解模式-->
    <context:component-scan base-package="com.spring.jdbc.transaction"></context:component-scan>

</beans>

2.5 Junit单元测试类

** 
* BuyBookServiceImpl Tester.
 * 注解配置事务管理方式的测试
* 
* @author <Authors name> 
* @since <pre>8�� 16, 2020</pre> 
* @version 1.0 
*/ 
public class BuyBookTest {


    private BuyBookService buyBookService;

    private BuyTwoBooksService buyTwoBooksService;

@Before
public void before() throws Exception {
    ApplicationContext ap=new ClassPathXmlApplicationContext("jdbc/JDBC-Context.xml");
    buyBookService=ap.getBean("buyBookServiceImpl", BuyBookService.class);
    buyTwoBooksService=ap.getBean("buyTwoBooksServiceImpl",BuyTwoBooksService.class);
}

@After
public void after() throws Exception { 
} 

/** 
* 
* Method: buyBook() 
* 
*/ 
@Test
public void testBuyBook() throws Exception {
    buyBookService.buyBook();
} 

@Test
public void testBuyTwoBooks() throws Exception{
    buyTwoBooksService.buyTwoBooks();
}

} 

以上是事务管理以注解方式实现的全过程,以xml方式实现的方法就不粘贴过来了,内容太多了,有需要的还是去GitHub查看吧

四、结语

本章主要是学习了spring的JDBC模块,重点是事务管理方面,spring的事务管理它的实现也是依靠于它的Aop模块的支持,这个在事务管理Xml的配置方式中可以很直观的看出来,但是最方便的方式肯定是使用@Transaction的注解配置方式。
可能在学习的过程中,有些关于基础性的数据库事务内容,没有写全,导致这章博客质量较低,因为这些东西在网上有太多比我理解深刻的博客可以参考了。
自此,spring的学习应该是到一个阶段了,下一阶段系统学习mybatis
如果有大神路过,请不吝赐教

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个关于Java Spring框架中配置JDBC连接DataSource的问题。在Spring中,我们可以使用以下配置来连接数据源: 1. 配置数据源 ``` <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> ``` 在这个配置中,我们使用了`DriverManagerDataSource`来创建数据源,你也可以使用其他的数据源,比如`BasicDataSource`、`C3P0DataSource`、`HikariDataSource`等。 2. 配置JdbcTemplate ``` <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> ``` 在这个配置中,我们使用了`JdbcTemplate`来执行SQL语句,这个类提供了一系列的方法,比如`queryForObject`、`queryForList`、`update`等,可以方便地执行SQL语句。 3. 使用JdbcTemplate ``` @Autowired private JdbcTemplate jdbcTemplate; public void someMethod() { String sql = "SELECT * FROM user WHERE id=?"; User user = jdbcTemplate.queryForObject(sql, new Object[]{1}, new BeanPropertyRowMapper<>(User.class)); } ``` 在这个示例中,我们使用了`JdbcTemplate`的`queryForObject`方法来执行SQL语句,并将结果转换为一个`User`对象。 希望这个回答能够帮到你,如果还有问题,可以继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值