6-基于Spring的框架-JDBC——6-1 引入及概述

概要

过度

我们前面基本介绍完了Spring的框架实现思路,现在我们以前面介绍的知识为基础,对常用的一些基于Spring的框架进行分离,目的是从java SE加特殊业务基本框架的角度对我们工作中使用的Spring定制框架进行解读。从而摘掉企业级框架的神秘面纱。

当然,虽然我一直对常用框架有一种读源码、即知其然也知其所以然的态度,但是要明白我们要用的本就是这些工具,我们需要的是这种探究的思想、设计模式的学习以及对疑难杂症的解决思路,而不是从头另搭一套东西出来。所以,我们在接下来的框架学习中力求用Java SE加基本框架的方法进行Spring框架的解读,但是不会再继续深入。

内容简介

本文回顾了jdbc的基本使用方法,并展示了 spring-jdbc工具的使用方法。下文将以本文的代码为切入点,解析spring-jdbc的实现逻辑。

前面对Spring框架的解析我们基本都是依照《Spring源码深度解析》一书,从这里开始,我们的阅读操作仍然以此书为一些指引,但是不在完全跟着他的思路走了。

所属环节

spring-jdbc引入及概览。

上下环节

上文:Spring框架详细解析

下文:无【如果硬要安排一个的话,应该算是数据库相关框架的总结吧】

JDBC

引入

我们在大学针对数据库操作进学习了一种框架:jdbc,这个是Java操作数据库的最基本的框架了。我们在操作数据库都是依靠SQL语句的,JDBC(Java DataBase Connectivity)也是接受SQL入参,并执行链接库、查询操作。

使用示例

我们先看一下基本的jdbc使用方法:

public static void main(String args[]) throws ClassNotFoundException, SQLException {
  // 在 com.mysql.cj.jdbc.Driver 类的静态代码块中进行了DriverManager的注册。
  Class.forName("com.mysql.cj.jdbc.Driver");
  Connection connection = DriverManager.getConnection("jdbc:mysql://","","");
  Statement statement = connection.createStatement();
  ResultSet resultSet = statement.executeQuery("select * from form");
  while (resultSet.next()){
    String x= resultSet.getString(1);
    System.out.println("x="+x);
  }
  //        statement.executeUpdate();
}

基本的jdbc的操作就是这样了,当然还有很多高级操作。比如:使用DataSource数据库连接池,使用PreparedStatement提高执行速度等等。

我们先看使用数据库连接池的操作:

public static void main(String args[]) throws ClassNotFoundException, SQLException, PropertyVetoException {
        // 在 com.mysql.cj.jdbc.Driver 类的静态代码块中进行了DriverManager的注册。
        ComboPooledDataSource ds = new ComboPooledDataSource();
        ds.setUser("");
        ds.setPassword("");
        ds.setDriverClass("com.mysql.cj.jdbc.Driver");
        ds.setJdbcUrl("jdbc:mysql://");
        ds.setInitialPoolSize(3);
        ds.setMaxPoolSize(10);
        ds.setMaxStatements(100);
        ds.setAcquireIncrement(2);

        Statement statement = ds.getConnection().createStatement();
        ResultSet resultSet = statement.executeQuery("select * from form");
        while (resultSet.next()){
            String x= resultSet.getString(1);
            System.out.println("x="+x);
        }
    }

接下来是使用PreparedStatement的操作:

public static void main(String args[]) throws ClassNotFoundException, SQLException {
  // 在 com.mysql.cj.jdbc.Driver 类的静态代码块中进行了DriverManager的注册。
  Class.forName("com.mysql.cj.jdbc.Driver");
  Connection connection = DriverManager.getConnection("jdbc:mysql://","","");
  PreparedStatement statement = connection.prepareStatement("select * from form");
  ResultSet resultSet = statement.executeQuery();
  while (resultSet.next()){
    String x= resultSet.getString(1);
    System.out.println("x="+x);
  }
}

总结

上面的所有操作其实思路都是相似的:

  1. 加载JDBC驱动
  2. 设置数据库相关信息【url、用户名、密码等等】
  3. 获得Connection
  4. 获得Statement
  5. 传入sql,获得执行结果

Spring JDBC

引入

上面进行了一些总结,我们很容易发现整体思路都差不多:

  • 其中1、2是一劳永逸的,这种设置在项目中不会变化
  • 3、4可以根据线程及其他的一些信息(例如事务)进行托管,以高效、合理的完成实现
  • 5和业务逻辑密切相关,涉及查询方式及数据转化,无法简化

所以,我们猜测Spring做的事应该分成两类:

  1. 对 JDBC驱动的加载、数据库的配置进行全局化设置:一次设置,多处复用。
  2. 接管ConnectionStatement的创建工作

我们使用Spring JDBC后只需要关注要执行的sql和结果映射即可。

使用示例

我们用最基本的xml配置来看吧,这个显的清楚一些:

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

  <!-- 1、声明数据源对象:C3P0连接池 -->
  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <!-- 加载jdbc驱动 -->
    <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
    <!-- jdbc连接地址 -->
    <property name="jdbcUrl" value="jdbc:mysql://"/>
    <!-- 连接数据库的用户名 -->
    <property name="user" value=""/>
    <!-- 连接数据库的密码 -->
    <property name="password" value=""/>
    <!-- 数据库的初始化连接数 -->
    <property name="initialPoolSize" value="3"/>
    <!-- 数据库的最大连接数 -->
    <property name="maxPoolSize" value="10"/>
    <!-- 数据库最多执行的事务 -->
    <property name="maxStatements" value="100"/>
    <!-- 连接数量不够时每次的增量 -->
    <property name="acquireIncrement" value="2"/>
  </bean>

  <!--  创建jdbcTemplate对象 -->
  <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"/>
  </bean>

  <bean id="userTemplate" class="UserTemplate" >
    <property name="jdbcTemplate" ref="jdbcTemplate"/>
  </bean>
</beans>

以上是所有的xml配置,其中:

  • 创建DataSource相关的配置实现了我们说的第一点——对 JDBC驱动的加载、数据库的配置进行全局化设置:一次设置,多处复用
  • 在我们的数据库增删改查操作和DataSource之间多了一层JdbcTemplate,猜测应该是这里进行了一些ConnectorStatement的封装工作。

我们继续看UserTemplate的Java代码:

public Long saveUser(User user){
  String sql = "INSERT INTO learn.form (creator, is_deleted, modifier, business_id, form_name, template_id, creation_code) VALUES (?,?,?,?,?,?,?)";
  KeyHolder keyHolder = new GeneratedKeyHolder();
  int result =  jdbcTemplate.update(
    new PreparedStatementCreator() {
      public PreparedStatement createPreparedStatement(Connection con) throws SQLException
      {
        PreparedStatement ps = getJdbcTemplate().getDataSource()
          .getConnection().prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
        ps.setString(1,user.getCreator());
        ps.setBoolean(2,user.isDeleted());
        ps.setString(3,user.getModifier());
        ps.setLong(4,user.getBusinessId());
        ps.setString(5,user.getFormName());
        ps.setLong(6,user.getTemplateId());
        ps.setString(7,user.getCreationCode());
        return ps;
      }
    }, keyHolder);
  if (result != 0){
    System.out.println("插入数据成功");
    return keyHolder.getKey().longValue();
  }
  return null;
}

public List<User> getByCreator(String creator){
  return jdbcTemplate.query("select * from form where creator = '"+creator+"'",new UserRowMapper());

我们很容易发现查询、修改(包括插入、删除)操作都依赖于JdbcTemplate的对应函数。我们在自己的代码中主要关注:

  1. SQL语句的构建操作
  2. 修改操作返回结果的带出设置
  3. 查询结果到POJO的映射

其中2、3都是各自的特殊属性,1是共通的属性。

总结

我们上面记录了对JdbcTemplate的使用方法,后面主要关注的是就是其中对ConnectionStatement的管理。

扩展

问题遗留

参考文献

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容