【数据库学习】数据库连接与JdbcTemplate

1,概念

1)数据库连接

java应用程序可以通过JDBC或Hibernate对数据库系统进行访问。JDBC或Hibernate提供了事务控制的接口,这些接口把事务控制相关的命令发送给数据库系统,由数据库系统来控制事务的隔离级别。
一般来说,java 应用程序访问数据库的过程是:

  1. 加载数据库驱动程序;
  2. 通过jdbc 建立数据库连接;
  3. 访问数据库,执行sql 语句;
  4. 断开数据库连接。

2)数据库连接池(Connection Pool)

常用的数据库连接池都实现了DataSource接口。

  1. 优点
    对数据库连接进行复用,从而减少了重复创建和删除连接的开销,提高了系统的性能和可扩展性。
  2. 缺点
    连接池会占用一定的内存和资源,在高并发环境中会出现连接池满的情况。需要合理设置连接池的参数。

1>HikariCP(推荐)

  1. 快速启动、低延迟。史上最快连接池。
    hikariCP的高性能得益于最大限度的避免锁竞争。
  2. 支持各种JDBC驱动程序和数据源。
  3. 在springboot2.0之后,采用的默认数据库连接池就是Hikari。优先级>tomcat jdbc pool>dbcp2

2>Druid

  1. 阿里巴巴开发的开源连接池;目前最好的数据库连接池。
  2. 功能强大:面向监控的连接池,内置功能丰富、同时可扩展;
  3. 支持JDBC和非JDBC数据源。

3>Apache Commons DBCP

@Configuration
public class DataSourceConfig {

        BasicDataSource ds =  new BasicDataSource ();
	   	//其它与C3P0一样
        return ds;
}
常见属性说明
initialSize=“10”初始化连接,连接池启动时创建的初始化连接数量(默认值为0)
maxActive=“80”最大活动连接,连接池中可同时连接的最大的连接数(默认值为8)
minIdle=“10”最小空闲连接,连接池中最小的空闲的连接数,低于这个数量会被创建新的连接(默认为0,该参数越接近maxIdle,性能越好,因为连接的创建和销毁,都是需要消耗资源的;但是不能太大,因为在机器很空闲的时候,也会创建低于minidle个数的连接,类似于jvm参数中的Xmn设置)
maxIdle=“60”最大空闲连接,连接池中最大的空闲的连接数,超过的空闲连接将被释放,如果设置为负数表示不限制(默认为8个,maxIdle不能设置太小,因为假如在高负载的情况下,连接的打开时间比关闭的时间快,会引起连接池中idle的个数上升超过maxIdle,而造成频繁的连接销毁和创建,类似于jvm参数中的Xmx设置)
maxWait=“3000”从池中取连接的最大等待时间,单位ms.当没有可用连接时,连接池等待连接释放的最大时间,超过该时间限制会抛出异常,如果设置-1表示无限等待(默认为无限)

注意事项:
maxIdle值与maxActive值应配置的接近:
当连接数超过maxIdle值后,刚刚使用完的连接(刚刚空闲下来)会立即被销毁。而不是想要的空闲M秒后再销毁起一个缓冲作用。若maxIdle与maxActive相差较大,在高负载的系统中会导致频繁的创建、销毁连接,连接数在maxIdle与maxActive间快速频繁波动,这不是想要的。高负载系统的maxIdle值可以设置为与maxActive相同或设置为-1(-1表示不限制),让连接数量在minIdle与maxIdle间缓冲慢速波动。

timeBetweenEvictionRunsMillis建议设置值:
minIdle要与timeBetweenEvictionRunsMillis配合使用才有用,单独使用minIdle不会起作用。

initialSize=“5”,会在tomcat一启动时,创建5条连接,效果很理想。但同时我们还配置了minIdle=“10”,也就是说,最少要保持10条连接,那现在只有5条连接,哪什么时候再创建少的5条连接呢?
1、等业务压力上来了, DBCP就会创建新的连接。
2、配置timeBetweenEvictionRunsMillis=“时间”,DBCP会启用独立的工作线程定时检查,补上少的5条连接。销毁多余的连接也是同理。

连接销毁的逻辑

DBCP的连接数会在initialSize - minIdle - maxIdle - maxActive 之间变化。变化的逻辑描述如下:
默认未配置initialSize(默认值是0)和timeBetweenEvictionRunsMillis参数时,刚启动tomcat时,连接数是0。当应用有一个并发访问数据库时DBCP创建一个连接。目前连接数量还未达到minIdle,但DBCP也不自动创建新连接已使数量达到minIdle数量(没有一个独立的工作线程来检查和创建)。随着应用并发访问数据库的增多,连接数也增多,但都与minIdle值无关,很快minIdle被超越,minIdle值一点用都没有。直到连接的数量达到maxIdle值,这时的连接都是只增不减的。 再继续发展,连接数再增多并超过maxIdle时,使用完的连接(刚刚空闲下来的)会立即关闭,总体连接的数量稳定在maxIdle但不会超过maxIdle。
但活动连接(在使用中的连接)可能数量上瞬间超过maxIdle,但永远不会超过maxActive。这时如果应用业务压力小了,访问数据库的并发少了,连接数也不会减少(没有一个独立的线程来检查和销毁),将保持在maxIdle的数量。
默认未配置initialSize(默认值是0),但配置了timeBetweenEvictionRunsMillis=“30000”(30秒)参数时,刚启动tomcat时,连接数是0。马上应用有一个并发访问数据库时DBCP创建一个连接。目前连接数量还未达到minIdle,每30秒DBCP的工作线程检查连接数是否少于minIdle数量,若少于就创建新连接直到达到minIdle数量。
随着应用并发访问数据库的增多,连接数也增多,直到达到maxIdle值。这期间每30秒DBCP的工作线程检查连接是否空闲了30分钟,若是就销毁。但此时是业务的高峰期,是不会有长达30分钟的空闲连接的,工作线程查了也是白查,但它在工作。到这里连接数量一直是呈现增长的趋势。
当连接数再增多超过maxIdle时,使用完的连接(刚刚空闲下来)会立即关闭,总体连接的数量稳定在maxIdle。停止了增长的趋势。但活动连接(在使用中的连接)可能数量上瞬间超过maxIdle,但永远不会超过maxActive。
这时如果应用业务压力小了,访问数据库的并发少了,每30秒DBCP的工作线程检查连接(默认每次查3条)是否空闲达到30分钟(这是默认值),若连接空闲达到30分钟,就销毁连接。这时连接数减少了,呈下降趋势,将从maxIdle走向minIdle。当小于minIdle值时,则DBCP创建新连接已使数量稳定在minIdle,并进行着新老更替。

4>Apache DBCP2

  1. 开源连接池;
  2. 支持JDBC1、JDBC2、JDBC3规范和JDBC的扩展API;
  3. 相比C3P0,DBCP的性能略有下降,但是在一些场景下,DBCP比C3P0更加稳定。

5>C3P0

  1. 开源连接池。
  2. 单线程的,在高并发的环境下性能会降低。
  3. 它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。
i>配置 C3P0 信息
  • application.properties
# SQLServer 数据库配置信息
c3p0.jdbcUrl=jdbc:sqlserver://localhost:1433;DatabaseName=game
c3p0.user=gm
c3p0.password=root
c3p0.driverClass=com.microsoft.sqlserver.jdbc.SQLServerDriver
c3p0.minPoolSize=2
c3p0.maxPoolSize=10
c3p0.maxIdleTime=30
c3p0.checkoutTimeout=30000
c3p0.acquireIncrement=3
c3p0.maxStatements=1000
c3p0.initialPoolSize=3
c3p0.idleConnectionTestPeriod=60
c3p0.acquireRetryAttempts=30
c3p0.acquireRetryDelay=1000
c3p0.breakOnAcquireFailure=true
c3p0.breakAfterAcquireFailure=false
c3p0.testConnectionOnCheckout=false

引入 C3P0 和 SQLServer 依赖:

<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.2</version>
</dependency>

<dependency>
    <groupId>com.microsoft.sqlserver</groupId>
    <artifactId>mssql-jdbc</artifactId>
    <version>7.0.0.jre8</version>
</dependency>
<!-- 引入 dbutils 依赖操作数据库 -->
<dependency>
    <groupId>commons-dbutils</groupId>
    <artifactId>commons-dbutils</artifactId>
    <version>1.6</version>
</dependency>

创建 C3P0 配置类:

@Configuration
public class C3p0Configuration {

    @Bean(name = "dataSource")
    @Primary // 用 @Primary 区分主数据源
    @ConfigurationProperties(prefix = "c3p0") // 指定配置文件中,前缀为 c3p0 的属性值
    public DataSource dataSource(){
        return DataSourceBuilder.create()
                .type(ComboPooledDataSource.class).build();
    }
}

ii>C3P0 多数据源配置:
@Configuration
@ConfigurationProperties(prefix = "spring.data.neo4j")
public class DataSourceConfig {
	String driverClassName;
    String jdbcUrl;
    String username;
    String password;
    String type;
	@Bean(name = "neo4jDataSource")
    public DataSource neo4jDataSource() throws PropertyVetoException {
        ComboPooledDataSource ds =  new ComboPooledDataSource();
        ds.setDriverClass(driverClassName);
        ds.setUser(username);
        ds.setPassword(password);
        ds.setJdbcUrl(jdbcUrl);
        //根据实际需要配置各种参数。
        return ds;
    }
}

yml文件中配置:
spring
   data:
    neo4j:
      driver-class-name: org.neo4j.jdbc.Driver
      jdbc-url: jdbc:neo4j:bolt://postgresql.host:7687
      uri: bolt://postgresql.host:7687
      username: neo4j
      password: ${spring.data.neo4j.password}
      type: ${spring.datasource.type}

//使用Spring的注入功能,可以把DataSource(数据库连接池)注册到jdbcTemplate中。
@Configuration
@EnableTransactionManagement
public class Neo4jJdbcConfig {

    @Autowired
    //Qualifier指明具体的实现类
    @Qualifier("neo4jDataSource")
    DataSource neo4jDataSource;

    @Bean(name = "neo4jJdbcTemplate")
    public JdbcTemplate neo4jJdbcTemplate() {
        return new JdbcTemplate(neo4jDataSource);
    }
}

//使用JdbcTemplate时,如果是多数据源
	@Autowired
    @Qualifier("neo4jJdbcTemplate")
    private JdbcTemplate neo4jJdbcTemplate;

6>tomcat jdbc pool

Tomcat 从 7.0 开始引入一个新的模块:Tomcat jdbc pool,在tomcat-jdbc包下。

  1. 近乎兼容 dbcp ,性能更高
  2. 异步方式获取连接,支持高并发应用环境
  3. 超简单,核心文件只有8个,比 c3p0 还少

2,JDBC(Java Data Base Connectivity,java数据库连接)

1)概念

  1. jdbc是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问;

2)使用

  1. 通过java.sql中的Connection连接数据库;
  2. 创建Statement或PreparedState执行SQL语句;
  3. 通过ResultSet获取返回结果集。
Class.forName("org.h2.Driver");
try(
Connection con = DriverManager.getConnection("jdbc:h2:mem:test_db");
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("select x from ...")
){
	while(resultSet.next()){
	log.info(resultSet.getInt(1));
	}
}catch(SQLException e){
	//handle SQL exceptions, perform tansaction rollback
}
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class JdbcConnection {
    public void connection() {
        PreparedStatement preparedStatement = null;
        Connection connection = null;
        ResultSet resultSet = null;
        try {
            //初始化对象
            //1.加载驱动 不同的数据库对应的驱动不同,同时需要引入lib/*.jar包或添加对应的maven依赖
            Class.forName("org.postgresql.Driver");
            //获取数据库连接。三个参数为:url、user、psw  不同数据库url格式不同
            connection = DriverManager.getConnection("jdbc:postgresql://127.0.0.1:5432/databaseName", "postgres", "psw");
            /**
             * 执行对应的sql语句
             * connection常用的方法有:
             * 1. createStatement()	创建向数据库发送sql的statement对象。
             * 2. prepareStatement(sql)	创建向数据库发送预编译sql的PrepareSatement对象。
             * 3. prepareCall(sql)	创建执行存储过程的callableStatement对象。
             * 4. setAutoCommit(boolean autoCommit)	设置事务是否自动提交。
             * 5. commit()	在链接上提交事务。
             * 6. rollback()	在此链接上回滚事务。
             */
            preparedStatement = connection.prepareStatement("create database lwhtest");

            /**
             *
             */
            boolean result = preparedStatement.execute();
            if (result) {
                System.out.println("create a connection success!");
            } else {
                System.out.println("create a connection fail!");
            }
        } catch (Exception e) {
            // TODO: handle exception
            System.out.println("error!");
        } finally {
            //释放资源:ResultSet, Statement和Connection对象
            try {
                if (preparedStatement != null)
                    preparedStatement.close();
                if (connection != null)
                    connection.close();
            } catch (Exception e2) {
                // TODO: handle exception
            }
        }
    }
}

3)Statement

  1. 用于在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句。
  2. 用于执行不带参数的简单SQL语句。
    带参数的sql执行用PreparedStatement代替,预编译防止sql注入。
  3. 每次执行sql语句,数据库都要执行sql语句的编译
    最好用于仅执行一次查询并返回结果的情形。
    单次执行效率高于PreparedStatement,批量sql执行由于PreparedStatement预编译效率更高。
方法含义
executeQuery(String sql)用于向数据发送查询语句。
executeUpdate(String sql)用于向数据库发送insert、update或delete语句
execute(String sql)用于向数据库发送任意sql语句
addBatch(String sql)把多条sql语句放到一个批处理中。
executeBatch()向数据库发送一批sql语句执行。
PreparedStatement pst=con.prepareStatement(“select * from users where name=? and password=?);
pst.setString(1, username);
pst.setString(2, password);
ResultSet rst=pst.executeQuery();

4)CallableStatement接口

扩展了 PreparedStatement(父接口),用来调用存储过程,它提供了对输出和输入/输出参数的支持。

5)ResultSet

ResultSet 对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,调用ResultSet.next() 方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据。(ResultSet跟普通的数组不同,索引从1开始而不是从0开始);

1>获取行

ResultSet提供了对结果集进行滚动的方法:

next():移动到下一行
Previous():移动到前一行
absolute(int row):移动到指定行
beforeFirst():移动resultSet的最前面。
afterLast() :移动到resultSet的最后面。
    ResultSet rs = null;
    //4.向数据库发sql,并获取代表结果集的resultset
    String sql = "select id,name,password,email,birthday from users";
    rs = st.executeQuery(sql);
    			
    //5.取出结果集的数据
    rs.afterLast();
    rs.previous();
    System.out.println("id=" + rs.getObject("id"));
    System.out.println("name=" + rs.getObject("name"));
    System.out.println("password=" + rs.getObject("password"));
    System.out.println("email=" + rs.getObject("email"));
    System.out.println("birthday=" + rs.getObject("birthday"));

2>获取值

ResultSet既然用于封装执行结果的,所以该对象提供的都是用于获取数据的get方法:

// 获取任意类型的数据
getObject(int index)
getObject(string columnName)

//获取指定类型的数据,例如:
getString(int index)
getString(String columnName)

3,Hibernate

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使java程序员可以随心所欲地使用对象编程思想来操纵数据库。目前使用较少。

4,JdbcTemplate

​JdbcTemplate是Spring对JDBC的封装,目的是使JDBC更加易于使用。
JdbcTemplate处理了资源的建立和释放。

1)管理JDBC连接

使用连接池配置。

2)执行SQL语句

在JdbcTemplate中执行SQL语句的方法大致分为3类:

1>execute

  1. 可以执行所有SQL语句
  2. 没有返回值,一般用于执行DDL语句。

2>queryXxx

用于DQL数据查询语句。

查询单行:

String sql = "select num,name,age from student where id = ?";
    RowMapper<stu> rowMapper = new BeanPropertyRowMapper<stu>(stu.class);
    stu s = jdbcTemplate.queryForObject(sql, rowMapper,5);//最后一个参数为id值

查询多行:

String sql = "select num,name,age from student where id > ?";
    RowMapper<stu> rowMapper = new BeanPropertyRowMapper<stu>(stu.class);
    List<stu> s = jdbcTemplate.query(sql, rowMapper,0);//最后一个参数为id值

单值查询:

String sql = "select count(name) from student";
    Long count = jdbcTemplate.queryForObject(sql, Long.class);

3>update

  1. 用于执行INSERT、UPDATE、DELETE等DML语句。
  2. 预编译、多参数
 String sql = "update student set name = ? where num = ?";
    jdbcTemplate.update(sql, "pink",0001);

3)批量插入:batchUpdate

  1. 开启批处理模式:
    在数据库地址上加上rewriteBatchedStatements=true ;这样访问数据库只需要一个SqlSession。
    减少往返数据库的次数,提高数据库访问性能。
  2. 预编译提高sql执行效率
    预编译就是将sql中的值通过占位符写入,sql语句模板化或者说参数化。一次编译、多次运行,省去了解析优化等过程。
    注意:预编译(useServerPrepStmts)和预编译缓存(cachePrepStmts)一定要同时开启或同时关闭。否则会影响执行效率
import org.springframework.jdbc.core.JdbcTemplate;

@Autowired
JdbcTemplate jdbcTemplate;

//返回值int[] 代表每次执行sql的更新条数
public int[] updateOrSaveBatch(String updateOrInsertSql, List<UserPo> userList) {
        return jdbcTemplate.batchUpdate(updateOrInsertSql,
                new BatchPreparedStatementSetter() {
                    @Override
                    public void setValues(PreparedStatement ps, int i) throws SQLException {
                        ps.setObject(1, userList.get(i).getId());
                        ps.setObject(2, userList.get(i).getName());
                    }
                    @Override
                    public int getBatchSize() {
                        return userList.size();
                    }
                });
    }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
JdbcTemplate是Spring Framework中的一个核心类,它可以通过简化JDBC的使用来简化数据库访问。使用JdbcTemplate连接数据库需要以下步骤: 1. 在Spring配置文件中配置数据源,例如使用org.apache.commons.dbcp.BasicDataSource。 2. 在Spring配置文件中配置JdbcTemplate Bean,将数据源注入到JdbcTemplate中。 3. 在Java代码中使用JdbcTemplate对象进行数据库操作,例如查询、插入、更新和删除。 以下是一个使用JdbcTemplate连接数据库的示例代码: ``` @Autowired private JdbcTemplate jdbcTemplate; public void queryData() { String sql = "SELECT * FROM users"; List<Map<String, Object>> userList = jdbcTemplate.queryForList(sql); for (Map<String, Object> user : userList) { System.out.println(user.get("name")); } } public void insertData(String name, int age) { String sql = "INSERT INTO users (name, age) VALUES (?, ?)"; jdbcTemplate.update(sql, name, age); } public void updateData(int id, String name) { String sql = "UPDATE users SET name = ? WHERE id = ?"; jdbcTemplate.update(sql, name, id); } public void deleteData(int id) { String sql = "DELETE FROM users WHERE id = ?"; jdbcTemplate.update(sql, id); } ``` 在这个示例中,我们使用@Autowired注解将JdbcTemplate对象注入到Java类中,并使用queryForList、update方法进行数据库操作。当我们查询数据时,我们使用queryForList方法将查询结果转换成一个List<Map<String, Object>>类型的对象,其中每一个Map对象代表一行查询结果。当我们插入、更新和删除数据时,我们使用update方法进行相应的操作。在update方法中,我们使用?号作为占位符,每一个?号对应一个参数,参数的值在方法的后面依次传入。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值