java数据库连接进化过程(JDBC)

Posted 爱喝啤酒的猴子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java数据库连接进化过程(JDBC)相关的知识,希望对你有一定的参考价值。

最近学习spring集成mybatis连接数据库,想对java连接数据库规范JDBC(JavaDatabase Connectivity)再系统的回顾一遍。这篇博客从JDBC最基础的操作讲起,穿插数据源的使用(DruidDataSource)、spring的JDBC模板jdbcTemplate,在spring中整合mybaits操作数据库等相关知识,简单分析JDBC操作数据库的简化过程。
使用工具版本:

  • 数据库: 6.0.11-alpha-community mysql Community Server (GPL)
  • mysq连接驱动包:5.1.6
  • druid数据源:1.1.15
  • spring:4.3.14.RELEASE
  • mybatis:3.4.1

JDBC直接操作数据库

还未出现spring框架甚至还未出现数据源的年代,前辈们都是使用原生的jdbc API来操作数据库。具体操作步骤如下:

  1. 加载数据库驱动类
    Class.forName(driver);
  2. 通过驱动管理工具类获取连接
    connection = (Connection) DriverManager.getConnection(dburl, username, password);
  3. 在java代码中编写sql语句
  4. 创建数据库操作对象(Statement或PreparedStatement)
  5. 执行数据库操作
  6. 获取并操作结果集
  7. 关闭数据库操作对象和连接对象
    下面是一个完整的示例:
public class DatabaseConnectionDemo1 
    private Connection connection = null;
    @Before
    public void before()
        String driver = "com.mysql.jdbc.Driver";
        String dburl = "jdbc:mysql://localhost:3306/testdemo1";
        String username = "root";
        String password = "*****";

        try 
            //加载驱动类
            Class.forName(driver);
            connection = (Connection) DriverManager.getConnection(dburl, username, password);
         catch (ClassNotFoundException e) 
            e.printStackTrace();
         catch (SQLException e) 
            e.printStackTrace();
        
    
    //插入操作
    @Test
    public void test1()
        int result = -1;
        String sql = "insert into person(name,age,gender) value(?,?,?)";
        PreparedStatement preparedStatement = null;
        try 
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,"steven");
            preparedStatement.setInt(2,25);
            preparedStatement.setString(3,"male");
            result = preparedStatement.executeUpdate();
            System.out.println(result);
            preparedStatement.close();
            connection.close();
         catch (SQLException e) 
            e.printStackTrace();
        
    
    //修改操作
    @Test
    public void test2()
        int result = -1;
        String sql = "update person set name = ? WHERE  id = ?";
        PreparedStatement preparedStatement = null;
        try 
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,"luuuuu");
            preparedStatement.setInt(2,1);
            result = preparedStatement.executeUpdate();
            System.out.println(result);
            preparedStatement.close();
            connection.close();
         catch (SQLException e) 
            e.printStackTrace();
        
    
    //查询操作
    @Test
    public void test3() 
        String sql = "select * from person";
        Statement statement = null;
        ResultSet rs = null;
        try 
            statement = connection.createStatement();
            rs =  statement.executeQuery(sql);
            while (rs.next())
                System.out.println(rs.getInt("id"));
                System.out.println(rs.getString("gender"));
                System.out.println(rs.getInt("age"));
                System.out.println(rs.getString("name"));
            
         catch (SQLException e) 
            e.printStackTrace();
        

    

可以看到数据库用户名密码等相关配置都硬编码在了代码中,如果数据库连接信息出现变动就需要改动代码重新编译,这不利于项目的维护。

使用数据源操作数据库

显然将数据库相关配置写到配置文件中由配置文件来管理能避免以上尴尬的情况。由此各种数据源被提出来,例如 DBCP 、C3P0、Druid 等。下面代码是以druid为例在spring中容器中配置数据源来管理数据库连接。
使用maven管理依赖:
pom.xml

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>$spring.version</version>
    </dependency>
        <!-- druid数据源 -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>$druid.version</version>
    </dependency>

jdbc配置文件:
jdbc.properties

#####################数据库配置################
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/testdemo1
jdbc.username=root
jdbc.password=********
jdbc.initialSize=1
jdbc.minIdle=1
#jdbc.maxIdle=10 过时配置项
validationQuery=SELECT 1

spring配置:
applicationcontext.xml

	<bean id="propertyConfigure"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>application.properties</value>
            </list>
        </property>
    </bean>
    <bean id="datasource1" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
    p:driverClassName="$jdbc.driverClassName"
    p:url="$jdbc.url"
    p:username="$jdbc.username"
    p:password="$jdbc.password"
    p:initialSize="$jdbc.initialSize"
    p:minIdle="$jdbc.minIdle"
    p:maxIdle="$jdbc.maxIdle">
    </bean>

测试使用:

 ApplicationContext context = new ClassPathXmlApplicationContext("applicationcontext.xml");
        BasicDataSource dataSource = (BasicDataSource) context.getBean("dataSource");
        String SQL_select = "select * from persion where id = ?";
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try
            conn = dataSource.getConnection();
            System.out.println("connect success!");
            stmt = conn.prepareStatement(SQL_select);
            stmt.setInt(1,1005);
            rs = stmt.executeQuery();
            Persion persion = new Persion();
            if(rs.next())
                persion.setId(rs.getInt("id"));
                persion.setName(rs.getString("name"));
                persion.setAge(rs.getInt("age"));
                persion.setGender(rs.getString("gender"));
                System.out.println(persion.toString());
            
        catch (Exception e)

        finally 
            if(rs != null)
                try
                    rs.close();
                catch (Exception e)

                
            
            if(stmt != null)
                try
                    stmt.close();
                catch (Exception e)

                
            
            if(conn != null)
                try
                    conn.close();
                catch (Exception e)

                
            
        

可以看到直接使用数据源可以避免在代码中硬编码数据库的配置信息。但每次操作数据库时都需要进行数据库连接对象、操作对象、结果集的获取和关闭,需要些大量的try catch语句,而这些代码本质上和业务无关,在业务开发过程中显然不是我们关注的重点,但又不得不些大量这样的代码。

使用spring提供的模板操作数据库

spring中提出了JDBC模板的概念,使用JDBC操作数据库,我们只需要关注业务代码,有关数据库连接、结果集等的获取与关闭都由模板来完成。
在spring4中提供了org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate来操作数据库。以下是一个简单使用示例:
spring配置:
applicationcontext.xml

<bean id="propertyConfigure"
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>application.properties</value>
        </list>
    </property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
    <constructor-arg ref="datasource1"/>
</bean>
<bean id="datasource1" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
p:driverClassName="$jdbc.driverClassName"
p:url="$jdbc.url"
p:username="$jdbc.username"
p:password="$jdbc.password"
p:initialSize="$jdbc.initialSize"
p:minIdle="$jdbc.minIdle"
p:maxIdle="$jdbc.maxIdle">
</bean>

注意这里将datasource1作为NamedParameterJdbcTemplate的构造器参数注入模板中。
操作数据库示例:

 NamedParameterJdbcTemplate jdbcTemplate = (NamedParameterJdbcTemplate) context.getBean("jdbcTemplate");
        if(jdbcTemplate instanceof NamedParameterJdbcTemplate)
            System.out.println("connect success!");
        
        Persion persion = (Persion) context.getBean("persionthirteen");
        String SQL_INSERT = "insert into persion(id,name,age,gender)" +
                " value (:id, :name, :age, :gender)";
        Map<String,Object> params = new HashMap<String,Object>();
        params.put("id",persion.getId());
        params.put("name",persion.getName());
        params.put("age",persion.getAge());
        params.put("gender",persion.getGender());
        int result = jdbcTemplate.update(SQL_INSERT,params);
        System.out.println(result);

从上面代码可以看到,再也不用在代码中些大量try catch语句,只需要专注业务代码即可。

spring整合mybatis

虽然spring的jdbc模板大大的简化了操作数据库的流程,但我们发现以上的代码中sql查询语句是直接写在了代码中,如果使用模板,在项目后期如果需要对sql进行优化,则又需要改动代码,这也不利于项目的维护。整合mybaits,利用mybatis将sql语句写到配置文件中避免硬编码带来的尴尬才是正道。下面是spring整合mybaits的示例.
pom.xml

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>$spring.version</version>
    </dependency>
        <!-- druid数据源 -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>$druid.version</version>
    </dependency>
       <!--mybatis-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>$mybatis.version</version>
    </dependency>
    <!--spring-mybatis-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>$mybatis_spring.version</version>
    </dependency>

applicationcontext.xml

  <context:component-scan base-package="com.steven.springdemo1.service"/>
   <context:property-placeholder location="classpath:config13.properties" ignore-unresolvable="true"/>
   <bean id = "datasource" class="com.alibaba.druid.pool.DruidDataSource"
   p:driverClassName="$jdbc.driverClassName"
   p:url="$jdbc.url"
   p:username="$jdbc.username"
   p:password="$jdbc.password"
   p:initialSize="$jdbc.initialSize"
   p:minIdle="$jdbc.minIdle"
   p:validationQuery="$validationQuery">
   </bean>
   <!--mybatis配置-->
   <bean id="seqSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
   p:dataSource-ref="datasource"
   p:mapperLocations="classpath:mapper/*Mapper.xml"
   p:typeAliasesPackage="com.steven.springdemo1.mapper">
   </bean>
   <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"
   p:basePackage="com.steven.springdemo1.mapper"
   p:sqlSessionFactoryBeanName="seqSessionFactory">
   </bean>

简单mapper接口及mapper.xml
mapper接口

public interface PersionMapper 
    int deleteByPrimaryKey(Integer id);

    int insert(Persion record);

    int insertSelective(Persion record);

    Persion selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(Persion record);

    int updateByPrimaryKey(Persion record);

mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.steven.springdemo1.mapper.PersionMapper" >
  <resultMap id="BaseResultMap" type="com.steven.springdemo1.pojo.Persion" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="name" property="name" jdbcType="VARCHAR" />
    <result column="age" property="age" jdbcType="INTEGER" />
    <result column="gender" property="gender" jdbcType="VARCHAR" />
  </resultMap>
  <sql id="Base_Column_List" >
    id, name, age, gender
  </sql>
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    from persion
    where id = #id,jdbcType=INTEGER
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
    delete from persion
    where id = #id,jdbcType=INTEGER
  </delete>
  <insert id="insert" parameterType="com.steven.springdemo1.pojo.Persion" >
    insert into persion (id, name, age, 
      gender)
    values (#id,jdbcType=INTEGER, #name,jdbcType=VARCHAR, #age,jdbcType=INTEGER, 
      #gender,jdbcType=VARCHAR)
  </insert>
  <insert id="insertSelective" parameterType="com.steven.springdemo1.pojo.Persion" >
    insert into persion
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        id,
      </if>
      <if test="name != null" >
        name,
      </if>
      <if test="age != null" >
        age,
      </if>
      <if test="gender != null" >
        gender,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        #id,jdbcType=INTEGER,
      </if>
      <if test="name != null" >
        #name,jdbcType=VARCHAR,
      </if>
      <if test="age != null" >
        #age,jdbcType=INTEGER,
      </if>
      <if test="gender != null" >
        #gender,jdbcType=VARCHAR,
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.steven.springdemo1.pojo.Persion" >
    update persion
    <set >
      <if test="name != null" >
        name = #name,jdbcType=VARCHAR,
      </if>
      <if test="age != null" >
        age = #age,jdbcType=INTEGER,
      </if>
      <if test="gender != null" >
        gender = #gender,jdbcType=VARCHAR,
      </if>
    </set>
    where id = #id,jdbcType=INTEGER
  </update>
  <update id="updateByPrimaryKey" parameterType="com.steven.springdemo1.pojo.Persion" >
    update persion
    set name = #name,jdbcType=VARCHAR,
      age = #age,jdbcType=INTEGER,
      gender = #gender,jdbcType=VARCHAR
    where id = #id,jdbcType=INTEGER
  </update>
</mapper>

这里由于介绍的重点是dao层,service层的代码省略了。下面是调用示例:

  @Test
   public void test1()
       Persion persion  = new Persion(10010,"steven lee",27,"male");
       ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
       PersonService personService = (PersonService) context.getBean("personService");
       System.out.println("create:"+personService.createPerson(persion));
       System.out.println("get:"+personService.getPersonbyId(10010));
       persion.setAge(26);
       System.out.println("update:"+personService.updatePerson(persion));
       System.out.println("delete:"+personService.deletePersonById(10010));
   

可以看到再也不用去在代码中写sql语句,代码变得更加清爽。

总结:

从JDBC操作数据到使用数据源、使用spring的模板再到在spring中整合mybatis操作数据库,这个过程中程序操作数据库的灵活性越来越高,代码耦合性越来越低,代码可维护性越来越好。

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

以上是关于java数据库连接进化过程(JDBC)的主要内容,如果未能解决你的问题,请参考以下文章

sql语句的进化

Java数据库连接——JDBC调用存储过程,事务管理和高级应用

猿进化系列13——一文搞懂MVC相关框架套路

请说说你对Hibernat的理解?JDBC和Hibernate各有什么优势和劣势?

Java数据库连接——JDBC调用存储过程,事务管理和高级应用

JDBC使用步骤过程