一、传统的JDBC编程
JDBC 我们一定不陌生,刚开始学习的时候,我们写过很多很多重复的模板代码。
pom.xml
<dependency> <groupId>mysqlgroupId> <artifactId>mysql-connector-javaartifactId> <version>5.1.49version> dependency>
创建 DBUtil 类
第一步我们可以把重复的模板代码提出来创建一个【DBUtil】数据库工具类:
public final class DBUtil { private DBUtil(){} private static final String DB_IP = "127.0.0.1"; private static final int DB_PORT = 3305; private static final String DATABASE = "spring"; private static final String ENCODING = "UTF-8"; private static final String LOGIN_NAME = "root"; private static final String PASSWORD = "123456"; static { try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { String url = String.format("jdbc:mysql://%s:%d/%s?useSSL=false&&characterEncoding=%s", DB_IP, DB_PORT, DATABASE, ENCODING); return DriverManager.getConnection(url, LOGIN_NAME, PASSWORD); } }
使用 try-catch 语句自动关闭资源
public class StudentServiceImpl { public Student getOne(int id) { String sql = "SELECT ID,NAME FROM SP_USER WHERE id = ?"; Student student = null; // 将 JDBC 声明变量包含在 try(..) 里将自动关闭资源 try (Connection con = DBUtil.getConnection(); PreparedStatement ps = con.prepareStatement(sql)) { // 设置参数 ps.setInt(1, id); // 执行SQL ResultSet rs = ps.executeQuery(); // 组装结果集返回 POJO if (rs.next()) { student = new Student(); student.setId(rs.getInt(1)); student.setName(rs.getString(2)); } } catch (SQLException e) { e.printStackTrace(); } return student; } }
其中Student实体类如下:
public class Student { private Integer id; private String name; private Integer age; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
二、Spring中的JDBC
要想使用 Spring 中的 JDBC 模块,就必须引入相应的 jar 文件:
<dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-jdbcartifactId> <version>${spring.version}version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-txartifactId> <version>${spring.version}version> dependency>
配置数据源有两种:
- 使用Spring内置的简单数据库配置
- 使用第三方数据库连接池
Spring内置数据库配置
Spring的内置类是org.springframework.jdbc.datasource.SimpleDriverDataSource
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import javax.sql.DataSource; public class StudentSv { private DataSource dataSource; public void setDataSource(DataSource dataSource) throws SQLException { this.dataSource = dataSource; } public Student getOne(int id) { String sql = "SELECT ID,NAME FROM SP_USER WHERE id = ?"; Student student = null; // 将 JDBC 声明变量包含在 try(..) 里将自动关闭资源 try (Connection con = this.dataSource.getConnection(); PreparedStatement ps = con.prepareStatement(sql)) { // 设置参数 ps.setInt(1, id); // 执行SQL ResultSet rs = ps.executeQuery(); // 组装结果集返回 POJO if (rs.next()) { student = new Student(); student.setId(rs.getInt(1)); student.setName(rs.getString(2)); } } catch (SQLException e) { e.printStackTrace(); } return student; } }
xml配置内容如下:
<bean id="dateSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource"> <property name="username" value="root"/> <property name="password" value="123456"/> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3305/spring?useSSL=false&characterEncoding=UTF-8"/> bean> <bean id="studentService" class="com.codedot.db.StudentSv"> <property name="dataSource" ref="dateSource">property> bean>
测试
public class DBTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); StudentSv studentSv = context.getBean(StudentSv.class); Student student = studentSv.getOne(1); System.out.println(student.getName()); } }
使用第三方数据源
上面配置的这个简单的数据源一般用于测试,因为它不是一个数据库连接池,只是一个很简单的数据库连接的应用。在更多的时候,我们需要使用第三方的数据库连接。
常用的有dbcp2、C3p0、Druid。
为什么要使用数据库连接池 、好处是什么?
① 资源重用 (连接复用):避免了频繁创建、释放连接引起的大量性能开销。增进系统的平稳性。
② 更快的系统响应速度:避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
③ 统一的连接管理,避免数据库连接泄露
dbcp2数据源
全限定名:org.apache.commons.dbcp2.BasicDataSource
需要添加:commons-dbcp2-xxx.jar、commons-pool2-xxx.jar
注意; dbcp2需要jdk1.7,否则会报错:Unsupported major.minor version 51.0
pom.xml
<dependency> <groupId>org.apache.commonsgroupId> <artifactId>commons-dbcp2artifactId> <version>2.7.0version> dependency> <dependency> <groupId>org.apache.commonsgroupId> <artifactId>commons-pool2artifactId> <version>2.7.0version> dependency>
dbcp2.properties
# BasicDataSource + mysql jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3305/spring?useSSL=false&characterEncoding=UTF-8 jdbc.username=root jdbc.password=123456 jdbc.maxTotal=100 jdbc.initialSize=10 jdbc.maxWaitMillis=60000 jdbc.minIdle=10 jdbc.maxIdle=15 jdbc.logAbandoned=true jdbc.removeAbandoned=true jdbc.removeAbandonedTimeout=10 jdbc.timeBetweenEvictionRunsMillis=10000 jdbc.numTestsPerEvictionRun=10 jdbc.minEvictableIdleTimeMillis=10000 jdbc.validationQuery=select 1 jdbc.testWhileIdle=true jdbc.testOnBorrow=true jdbc.defaultAutoCommit=true jdbc.defaultReadOnly=false
xml配置
<context:property-placeholder location="classpath:dbcp2.properties" /> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="maxTotal" value="${jdbc.maxTotal}" /> <property name="minIdle" value="${jdbc.minIdle}" /> <property name="maxIdle" value="${jdbc.maxIdle}" /> <property name="initialSize" value="${jdbc.initialSize}" /> <property name="logAbandoned" value="${jdbc.logAbandoned}" /> <property name="removeAbandonedOnBorrow" value="${jdbc.removeAbandoned}" /> <property name="removeAbandonedTimeout" value="${jdbc.removeAbandonedTimeout}" /> <property name="maxWaitMillis" value="${jdbc.maxWaitMillis}" /> <property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}" /> <property name="numTestsPerEvictionRun" value="${jdbc.numTestsPerEvictionRun}" /> <property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}" /> <property name="validationQuery" value="${jdbc.validationQuery}" /> <property name="testOnBorrow" value="${jdbc.testOnBorrow}" /> <property name="defaultReadOnly" value="${jdbc.defaultReadOnly}" /> bean> <bean id="studentService" class="com.codedot.db.StudentSv"> <property name="dataSource" ref="dataSource">property> bean>
C3p0数据源
全限定名:com.mchange.v2.c3p0.ComboPooledDataSource
需要添加:c3p0-xxx.jar、mchange-commons-java-xxx.jar
pom.xml
<dependency> <groupId>com.mchangegroupId> <artifactId>c3p0artifactId> <version>0.9.5.5version> dependency> <dependency> <groupId>com.mchangegroupId> <artifactId>mchange-commons-javaartifactId> <version>0.2.19version> dependency>
c3p0.properties
# ComboPooledDataSource + mysql jdbc.driverClass=com.mysql.jdbc.Driver jdbc.jdbcUrl=jdbc:mysql://localhost:3305/spring?useSSL=false&characterEncoding=UTF-8 jdbc.user=root jdbc.password=123456 jdbc.minPoolSize=1 jdbc.maxPoolSize=100 jdbc.initialPoolSize=5 jdbc.maxIdleTime=60 jdbc.acquireIncrement=10 jdbc.maxStatements=10 jdbc.idleConnectionTestPeriod=30 jdbc.acquireRetryAttempts=30 jdbc.breakAfterAcquireFailure=true jdbc.testConnectionOnCheckout=false jdbc.automaticTestTable=true jdbc.checkoutTimeout=15000 jdbc.numHelperThreads=10 jdbc.testConnectionOnCheckin=true
xml配置
<context:property-placeholder location="classpath:c3p0.properties" /> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.driverClass}" /> <property name="jdbcUrl" value="${jdbc.jdbcUrl}" /> <property name="user" value="${jdbc.user}" /> <property name="password" value="${jdbc.password}" /> <property name="minPoolSize" value="${jdbc.minPoolSize}" /> <property name="maxPoolSize" value="${jdbc.maxPoolSize}" /> <property name="initialPoolSize" value="${jdbc.initialPoolSize}" /> <property name="maxIdleTime" value="${jdbc.maxIdleTime}" /> <property name="acquireIncrement" value="${jdbc.acquireIncrement}" /> <property name="maxStatements" value="${jdbc.maxStatements}" /> <property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}" /> <property name="acquireRetryAttempts" value="${jdbc.acquireRetryAttempts}" /> <property name="breakAfterAcquireFailure" value="${jdbc.breakAfterAcquireFailure}" /> <property name="testConnectionOnCheckout" value="${jdbc.testConnectionOnCheckout}" /> <property name="automaticTestTable" value="${jdbc.automaticTestTable}" /> <property name="checkoutTimeout" value="${jdbc.checkoutTimeout}" /> <property name="numHelperThreads" value="${jdbc.numHelperThreads}" /> <property name="testConnectionOnCheckin" value="${jdbc.testConnectionOnCheckin}" /> bean> <bean id="studentService" class="com.codedot.db.StudentSv"> <property name="dataSource" ref="dataSource">property> bean>
Druid数据源
Druid是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、PROXOOL等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB连接池,号称是目前最好的连接池。
全限定名:com.alibaba.druid.pool.DruidDataSource
需要添加:druid-xxx.jar、commons-logging-1.2.jar
pom.xml
<dependency> <groupId>com.alibabagroupId> <artifactId>druidartifactId> <version>1.1.23version> dependency> <dependency> <groupId>commons-logginggroupId> <artifactId>commons-loggingartifactId> <version>1.2version> dependency>
druid.properties
# DruidDataSource + mysql jdbc.name=druid-1 jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3305/spring?useSSL=false&characterEncoding=UTF-8 jdbc.username=root jdbc.password=123456 jdbc.initialSize=1 jdbc.maxActive=10 jdbc.minIdle=1 jdbc.maxWait=10000 jdbc.poolPreparedStatements=true jdbc.maxOpenPreparedStatements=20 jdbc.validationQuery=select 1 jdbc.testOnBorrow=true jdbc.testOnReturn=false jdbc.testWhileIdle=true jdbc.timeBetweenEvictionRunsMillis=60000 jdbc.minEvictableIdleTimeMillis=300000 jdbc.filters=stat jdbc.defaultAutoCommit=true
xml配置
<context:property-placeholder location="classpath:druid.properties" /> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="name" value="${jdbc.name}" /> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="initialSize" value="${jdbc.initialSize}" /> <property name="maxActive" value="${jdbc.maxActive}" /> <property name="minIdle" value="${jdbc.minIdle}" /> <property name="maxWait" value="${jdbc.maxWait}" /> <property name="poolPreparedStatements" value="${jdbc.poolPreparedStatements}" /> <property name="maxOpenPreparedStatements" value="${jdbc.maxOpenPreparedStatements}" /> <property name="validationQuery" value="${jdbc.validationQuery}" /> <property name="testOnBorrow" value="${jdbc.testOnBorrow}" /> <property name="testOnReturn" value="${jdbc.testOnReturn}" /> <property name="testWhileIdle" value="${jdbc.testWhileIdle}" /> <property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}" /> <property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}" /> <property name="filters" value="${jdbc.filters}" /> <property name="defaultAutoCommit" value="${jdbc.defaultAutoCommit}" /> bean> <bean id="studentService" class="com.codedot.db.StudentSv"> <property name="dataSource" ref="dataSource">property> bean>