Spring使用JDBC

Spring的数据访问哲学

简介

当我们使用传统的JDBC操作数据库的时候,我们必须初始化数据访问框架、打开连接、处理各种异常和关闭连接。而Spring集成了多种数据访问技术。不管使用哪种,Spring都能帮我们消除持久化代码中那些单调枯燥的数据访问逻辑。我们可以依赖Spring来处理底层的数据访问,这样我们就可以专注于应用程序中数据的管理了。

了解Spring的数据访问异常体系

当使用 JDBC 与数据库进行交互遇见错误的时候,将会抛出名为 SQLException 的异常。如果不强制捕获SQLException的话,几乎无法使用JDBC做任何事情。SQLException表示在尝试访问数据库的时候出现了问题,但是这个异常却没有告诉你哪里出错了以及如何处理。
可能导致抛出SQLException的常见问题包括:

  • 应用程序无法连接数据库;
  • 要执行的查询存在语法错误;
  • 查询中所使用的表和/或列不存在;
  • 试图插入或更新的数据违反了数据库约束;

SQLException的问题在于捕获到它的时候该如何处理。事实上,能够触发SQLException的问题通常是不能在catch代码块中解决的。大多数抛出SQLException的情况表明发生了致命性错误。
如果无法从SQLException中恢复,那为什么我们还要强制捕获它呢?
即使对某些SQLException有处理方案,我们还是要捕获SQLException并查看其属性才能获知问题根源的更多信息。这是因为SQLException被视为处理数据访问所以问题的通用异常。对于所有的数据访问问题都会抛出SQLException,而不是对每种可能的问题都会有不同的异常类型。

Spring所提供的平台无关的持久化异常

不同于JDBC,Spring提供了多个数据访问异常,分别描述了它们抛出时所对应的问题。
从表中可以看出,Spring为读取和写入数据库的几乎所有错误都提供了异常。
数据访问异常
看!不用写catch代码块

表中没有体现出来的一点就是这些异常都继承自DataAccessExecption。DataAccessExecption的特殊之处在于它时一个非检查型异常。换句话说,没有必要捕获Spring所抛出的数据访问异常(如果,你想的话也可以)。
为了利用Spring的数据访问异常,我们必须使用Spring所支持的数据访问模板。

数据访问模板化

Spring将数据访问过程中固定的和可变的部分明确划分为两个不同的类:模板(template)和回调(callback)。模板管理过程中固定的部分,而回调处理自定义的数据访问代码。
针对不同的持久化平台,Spring提供了多个可选的模板。
模板
在声明模板和Repository之前,我们需要在Spring中配置一个数据源用来连接数据库。

配置数据源

Spring提供了在Spring上下文中配置数据源Bean的多种方式。

  • 通过JDBC驱动程序定义的数据源;
  • 通过JNDI查找的数据源;
  • 连接池的数据源;

使用JNDI数据源(Java Nameing And Directory Interface,Java命名与目录接口)

Spring应用程序经常部署在Java EE应用服务器中,如Tomcat。这些服务器允许你配置通过JNDI获取数据源。这种配置的好处在于数据源完全可以在应用程序之外管理,这样应用程序只需要在访问数据库的时候查找数据源就可以了。

RootConfig.java

@Bean
    public JndiObjectFactoryBean dataSource()
    {
        JndiObjectFactoryBean jndiObjectFB = new JndiObjectFactoryBean();
        jndiObjectFB.setJndiName("jdbc/mysql");  //与配置的Resource的name属性一致
        jndiObjectFB.setResourceRef(true);       //引用
        jndiObjectFB.setProxyInterface(DataSource.class); //设置代理接口,对应下面的type属性
        return jndiObjectFB;
    }

Tomcat中配置数据源
方式一(Context.xml)

<!--
  |- name:表示以后要查找的名称。通过此名称可以找到DataSource,此名称可任意更换。          
  |- auth:由容器进行授权及管理,指的用户名和密码是否可以在容器上生效
  |- type:此名称所代表的类型,现在为javax.sql.DataSource
  |- maxActive:表示一个数据库在此服务器上所能打开的最大连接数
  |- maxIdle:表示一个数据库在此服务器上维持的最小连接数
  |- maxWait:最大等待时间。10000毫秒
  |- username:数据库连接的用户名
  |- password:数据库连接的密码
  |- driverClassName:数据库连接的驱动程序
  |- url:数据库连接的地址
-->
<Resource   
        name="jdbc/mysql"  
        auth="Container"   
        type="javax.sql.DataSource"  
        maxActive="100"   
        maxIdle="30"   
        maxWait="10000"  
        username="root"   
        password="123456"  
        driverClassName="com.mysql.jdbc.Driver"  
        url="jdbc:mysql://localhost:3306/book"/>

方式二(server.xml)
打开server.xml配置文件,可以看到里面自带的一个全局JNDI配置,如下图所示:
这里写图片描述
编辑server.xml文件,添加全局JNDI数据源配置,配置如下:

<GlobalNamingResources>
    <!-- Editable user database that can also be used by
         UserDatabaseRealm to authenticate users
    -->
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
   <Resource   
        name="jdbc/mysql"  
        auth="Container"   
        type="javax.sql.DataSource"  
        maxActive="100"   
        maxIdle="30"   
        maxWait="10000"  
        username="root"   
        password="123456"  
        driverClassName="com.mysql.jdbc.Driver"  
        url="jdbc:mysql://localhost:3306/book"/>  
  </GlobalNamingResources>

context.xml中添加引用

<ResourceLink name="jdbc/mysql" global="jdbc/mysql" type="javax.sql.DataSource"/>

注:conf配置文件里web.xml、server.xml、context.xml的区别
web.xml好像在你的每一个项目里也会有个web.xml,主要配置servlet这些的,如果在tomcat里的web.xml,应该对所有的项目都有效.
server.xml是对tomcat的设置,可以设置端口号,添加虚拟机这些的,是对服务器的设置
context应该也是正对项目的,你在server.xml中的每个虚拟机里host标签里都可以添加context标签,以表示该虚拟机对应哪一个项目

使用数据源连接池

方式一:Apache Commons DBCP

@Bean
        public BasicDataSource dataSource() {
            BasicDataSource dataSource = new BasicDataSource();
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://localhost:3306/book");
            dataSource.setUsername("root");
            dataSource.setPassword("123456");
            dataSource.setInitialSize(5);
            return dataSource;
        }

DBCP
方式二:c3p0

@Bean
    public ComboPooledDataSource dataSource() throws PropertyVetoException {
        ComboPooledDataSource ds = new ComboPooledDataSource();
        ds.setDriverClass("com.mysql.jdbc.Driver");
        ds.setJdbcUrl("jdbc:mysql://localhost:3306/book");
        ds.setUser("root");
        ds.setPassword("123456");
        return ds;
    }

需导入c3p0的jar包。

基于JDBC驱动的数据源

Spring中,通过JDBC驱动定义数据源是最简单的配置方式。Spring提供了三个这样的数据源类(都位于org.springframework.jdbc.datasource包)供选择:

  • DriverManagerDataSource: 每个连接请求都会返回一个新建的连接,没有进行池化管理;
  • SimpleDriverDataSource: 与DriverManagerDataSource的工作方式相似,但是它直接使用JDBC驱动;
  • SingleConnectionDataSource: 在每个连接请求时都会返回同一个连接。SingleConnectionDataSource不是严格意义上的连接池数据源,但是可以将其视为只有一个连接的池;
*@Bean
        public DataSource dataSource() {
           DriverManagerDataSource dataSource = new DriverManagerDataSource();
            dataSource.setDriverClassName("com.mysql.jdbc.Driver"); 
            dataSource.setUrl("jdbc:mysql://localhost:3306/book");
            dataSource.setUsername("root");
            dataSource.setPassword("123456");
            return dataSource;
        }

需要Spring-tx.jar 与Spring-jdbc.jar。

使用嵌入式的数据源

嵌入式数据库作为应用的一部分运行,而不是应用连接的独立数据库服务器。

@Bean
    public DataSource dataSource() 
    {
        return new EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.HSQL)  //指定数据库
                .addScript("classpath:database/schme.sql")
                .addScript("classpath:database/test-data.sql")
                .build();
    }

第一个引用了schme.sql,它包含了在数据库创建表的SQL;第二个引用了test-data.sql,用来将测试数据填充到数据库中。
这种方式我们也没有用过。

在Spring中使用JDBC

失控的JDBC代码

        Connection conn = null;// connection
        PreparedStatement preState = null;// prepared statement
        ResultSet resultSet = null;// resultset
        try {
            // load driver
            Class.forName("com.mysql.jdbc.Driver");

            // get connection
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/ibatis_test", "root", "3713");

            /* sql statement */
            String querySql = "SELECT * FROM USERS WHERE USERNAME = ?";

            // prepare statement
            preState = conn.prepareStatement(querySql);

            // set parameter
            preState.setString(1, "michael");

            // execute query
            resultSet = preState.executeQuery();

            // iterate result set
            while (resultSet.next()) {
                System.out.println(resultSet.getString("id") + "\t" + resultSet.getString("username") + "\t" + resultSet.getString("password"));
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }

        // close streams seperately
        try {
            if (null != resultSet) {
                resultSet.close();
            }
            if (null != preState) {
                preState.close();
            }
            if (null != conn) {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

这么多行就为了查询一条记录。

使用JDBC模板

Sprng的JDBC框架承担了资源管理和异常处理的工作,从而简化了JDBC代码。Sprng为JDBC提供了三个模板类供选择:

  • JdbcTemplate:最基本的Sprng JDBC模板,支持简单的JDBC数据库访问功能以及基于索引参数的查询;
  • NamedParameterJdbcTemplate:该模板类执行查询时可以将值以命名参数的形式绑定到SQL中,而不是简单的索引;
  • SimpleJdbcTemplate:已经被废弃,不说了;
    只有在你需要使用命名参数的时候,才需要使用NamedParameterJdbcTemplate。所以JdbcTemplate是最好的方案。
@Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource)
    {
        return new JdbcTemplate(dataSource);
    }
@Autowired
private JdbcTemplate jdbcTemplate;   //注入

增删改查操作

    //插入
    public void add(Spittle spittle)
    {   
        String sql = "insert  into t_admin(adminId,adminname,adminpwd) values ('1',?,?)";
        jdbcTemplate.update(sql, new Object[]{spittle.getName(),spittle.getPassword()});        
    }
    //删除
    public  void delete(String id) 
    {  
            String sql = "delete from t_admin where adminId = ?";  
            Object args[] = new Object[]{id};  
            jdbcTemplate.update(sql,args);             
    }    
    //更新  
    public  void update(Spittle spittle) 
    {  
            String sql = "update t_admin set adminname = ? where adminId = ?";  
            Object args[] = new Object[]{spittle.getName(),spittle.getId()};  
            jdbcTemplate.update(sql,args);      
    }  
    //查询返回某一个值:查询表中数据总数
    public void queryForOne()
    {
        String sql = "select count(*) from t_admin ";
        int count = jdbcTemplate.queryForObject(sql, Integer.class);
        System.out.println("数据总数:" + count);
    }       
        /**
         * 功能:查询返回单个对象
         * 步骤:新建MyRowMapper类实现RowMapper接口,重写mapRow方法,指定返回User对象
         */    
        public void queryForObject() {
            String sql = "select * from t_admin where adminname= ?";
         //新建MyRowMapper类实现RowMapper接口,重写mapRow方法,指定返回User对象
            User user = jdbcTemplate.queryForObject(sql, new MyRowMapper(), "Tom");
            System.out.println(user);
        }

        /**
         * 功能:查询返回对象集合
         * 步骤:新建MyRowMapper类实现RowMapper接口,重写mapRow方法,指定返回User对象
         */
        public void queryForList() {
            String sql = "select * from user";
           //第三个参数可以省略
            List<User> users = jdbcTemplate.query(sql, new MyRowMapper());
            System.out.println(users);
        }

其它方法需想要了解的话,可以百度看看。因为我的SQL语句写的特别烂,所以我都基本用Hibernate。
以上只是学习Spring实战所写的笔记,如有错误,请指正。谢谢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值