目录
1. JDBC基本概念
2. 快速入门
3. 对JDBC中各个接口和类详解
JDBC
1. 概念:Java DataBase Connectivity(Java 数据库连接),Java语言操作数据库。
* JDBC本质:官方(SUN公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
2. 快速入门:
步骤:
1. 导入驱动jar包
2. 注册驱动
3. 获取数据库连接对象Connection
4. 定义sql
5. 获取执行sql语句的对象Statement
6. 执行sql,接受返回结果
7. 处理结果
8. 释放资源
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class JdbcDemo {
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/com?serverTimezone=UTC","root","123");
String sql="update emp set age=22 where id=2";
Statement stmt = conn.createStatement();
int count=stmt.executeUpdate(sql);
System.out.println(count);
stmt.close();
conn.close();
}
}
3. 详解各个对象
①DriverManager:告诉程序该使用哪一个数据库驱动jar
Ⅰ 注册驱动:告诉程序该使用哪一个数据库驱动jar
static void registerDriver(Driver driver):注册与给定的驱动程序 DriverManager。
写代码使用:Class.forName("com.sql.jdbc.Driver");
通过查看源码发现:在com.mysql.jdbc.Driver类中存在静态代码块:如下
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
注意:mysql5之后的驱动jar包可以省略注册驱动的步骤
Ⅱ 获取数据库连接
*方法:static Connection getConnetion(String url,String user,String password)
*参数:
url:指定连接的路径
jdbc:mysql://ip地址(域名):端口号/数据库名称
jdbc:mysql://localhost:3306/db3
user:用户名
password:密码
②Connection:数据库连接对象
Ⅰ 获取执行sql的对象
* Statement createStatement()
* PreparedStatement prepareStatement(String sql)
Ⅱ 管理事务
* 开启事务:SetAutoCommit(boolean autoCommit):调用该方法设置参数为false,即开启事务
* 提交事务:commit()
* 回滚事务:rollback()
③Statement:执行sql的对象
Ⅰ boolean execute(String sql):可以执行任意的sql 了解
Ⅱ int executeUpdate(String sql):执行DML(insert、update、delete)语句、DDL(create、alter、drop)语句
*返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功,返回值>0的则执行成功,反之,则失败。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbmDemo1 {
public static void main(String[] args) {
Connection conn=null;
Statement cstm=null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/com?serverTimezone=UTC", "root", "123");
cstm = conn.createStatement();
String sql="update emp set age=25 where id=6";
int count = cstm.executeUpdate(sql);
if(count>0){
System.out.println("bingo");
}else{
System.out.println("lose");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (cstm!=null){
try {
cstm.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
Ⅲ ResultSet executeQuery(String sql):执行DQL(select)语句
④ResultSet:结果集对象,封装查询结果
*next():游标向下移动一行
*getXXX(参数):获取数据
*XXX:代表数据类型
import java.sql.*;
public class JdbcDomo2 {
public static void main(String[] args) {
Connection conn=null;
Statement cstm=null;
ResultSet resultSet=null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/com?serverTimezone=UTC", "root", "123");
cstm = conn.createStatement();
String sql="select * from emp";
resultSet = cstm.executeQuery(sql);
while(resultSet.next()){
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
int dep_id = resultSet.getInt("dep_id");
System.out.println(id+"-"+name+"-"+age+"-"+dep_id);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (cstm!=null){
try {
cstm.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
⑤PreparedStatement:执行sql的对象
Ⅰ SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接,会造成安全性问题
1.输入用户随便,输入密码:a' or 'a'='a
2.sql:select * from user where username='fhdsjkf' and password='a' or 'a'='a'
Ⅱ 解决sql注入问题:使用PreparedStatement对象来解决
Ⅲ 预编译的sql:参数使用?作为占位符
Ⅳ 步骤:
1. 导入驱动jar包
2. 注册驱动
3. 获取数据库连接对象Connection
4. 定义sql
注意:sql的参数使用?作为占位符,如:select * from user where username=? and password=?;
5. 获取执行sql语句的对象 PreparedStatement Connection.prepareStatement(String sql)
6. 给?赋值:
方法:setXXX(参数1,参数2)
参数1:?的位置编号从1开始
参数2:?的值
7. 执行sql ,接受返回结果,不需要传递sql语句
8. 处理结果
9. 释放资源
Ⅴ 注意:后期都会使用PreparedStatement来完成增删改查的所有操作
* 可以放置SQL注入
* 效率更高
import java.sql.*;
import java.util.Scanner;
public class login {
public static void main(String[] args) throws SQLException {
Connection conn=null;
Statement cstm=null;
PreparedStatement preparedStatement=null;
ResultSet resultSet=null;
conn=JdbcUtils.getConnection();
Scanner sca=new Scanner(System.in);
int Id=sca.nextInt();
String password=sca.next();
String sql="select * from users where id=? and password=?";
preparedStatement = conn.prepareStatement(sql);
preparedStatement.setInt(1,Id);
preparedStatement.setString(2,password);
resultSet = preparedStatement.executeQuery();
if (resultSet.next()){
System.out.println("登陆成功");
}
else{
System.out.println("登陆失败");
}
JdbcUtils.close(preparedStatement,conn,resultSet);
}
}
~
抽取JDBC工具类:JDBCUtils
* 目的:简化书写
* 分析:
1.注册驱动
2.抽取一个方法获取连接对象
*需求:不想传递参数,还得保证工具的通用性
*解决:配置文件
jdbc.properties
url=
user=
password=
3.抽取一个方法释放资源
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String url;
private static String user;
private static String password;
private static String driver;
static {
Properties pro=new Properties();
ClassLoader classLoader=JdbcUtils.class.getClassLoader();
URL res = classLoader.getResource("jdbc.properties");
String path=res.getPath();
System.out.println(path);
try {
pro.load(new FileReader(path));
} catch (IOException e) {
e.printStackTrace();
}
url=pro.getProperty("url");
user=pro.getProperty("user");
password=pro.getProperty("password");
driver=pro.getProperty("driver");
}
public static Connection getConnection() {
Connection conn = null;
try {
conn = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void close(Statement stmt,Connection conn){
if (stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(Statement stmt, Connection conn, ResultSet resultSet){
if (stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
JDBC控制事务:
1. 事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
2. 操作:
2.1 开启事务
2.2 提交事务
2.3 回滚事务
3. 使用Connection对象来管理事务
3.1 开启事务:setAutoCommit(boolean autoCommit):调用该方法是指参数为false,即开启事务
3.2 提交事务:commit()
3.3 回滚事务:rollback()
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JdbcDemo4 {
public static void main(String[] args) {
Connection connection = JdbcUtils.getConnection();
PreparedStatement preparedStatement1 = null;
PreparedStatement preparedStatement2 = null;
try {
connection.setAutoCommit(false);
preparedStatement1 = connection.prepareStatement("update accounts set property=property - ? where id=?");
preparedStatement2 = connection.prepareStatement("update accounts set property=property + ? where id=?");
preparedStatement1.setDouble(1,500);
preparedStatement1.setInt(2,1);
preparedStatement2.setDouble(1,500);
preparedStatement2.setInt(2,2);
System.out.println("______________________________________");
preparedStatement1.executeUpdate();
int i=3/0;
System.out.println("______________________________________");
preparedStatement2.executeUpdate();
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
try {
System.out.println("shibai");
connection.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}finally {
JdbcUtils.close(preparedStatement1,null);
JdbcUtils.close(preparedStatement2,connection);
}
}
}
~
数据库连接池
1. 概念:其实就是一个容器(集合),存放数据库连接的容器
当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据时,从容其中获取连接对象,用户访问完后,会将连接对象归还给容器。
2. 好处:
2.1 节约资源
2.2. 用户访问高效
3. 实现:
3.1 标准接口:Datasource javax.sql包下的
3.1.1 方法:
* 获取连接:getConnection()
* 归还连接:如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会在关闭连接了,而是归还连接。
3.1.2 一般我们不去实现它,有数据库厂商来实现
* C3P0:数据库连接池技术
* Druid:数据库连接池实现技术,由阿里巴巴提供
4. C3P0:数据库连接池技术
下载地址:[C3P0](https://www.mchange.com/projects/c3p0/)
步骤:
①导入jar包(两个)c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar
②定义配置文件:
* 名称:c3p0.properties 或者 c3p0-config.xml(必须)
* 路径:直接将文件放在src目录下即可。
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/com?serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">123</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">20</property>
<property name="minPoolSize">5</property>
<property name="maxStatements">200</property>
</default-config>
<named-config name="mysql">
<property name="acquireIncrement">50</property>
<property name="initialPoolSize">100</property>
<property name="minPoolSize">50</property>
<property name="maxPoolSize">1000</property><!-- intergalactoApp adopts a different approach to configuring statement caching -->
<property name="maxStatements">0</property>
<property name="maxStatementsPerConnection">5</property>
</named-config>
</c3p0-config>
③连接池对象 ComboPooledDataSource
④获取连接:getConnection
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class C3P0Demo {
public static void main(String[] args) throws SQLException {
DataSource ds=new ComboPooledDataSource();
for(int i=0;i<11;i++){
Connection conn=ds.getConnection();
System.out.println(conn);
if(i==5){
conn.close();
}
}
}
}
5.Druid:数据库连接池实现技术,由阿里巴巴提供
[下载地址](https://github.com/alibaba/druid/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98)
5.1 步骤
5.1.1 导入jar包 druid-1.0.9.jar
5.1.2 定义配置文件
* 是propertie形式的
* 可以叫任意名字,可以放在任意目录下
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/com?serverTimezone=UTC
username=root
password=123
initialSize=5
maxActive=10
maxWait=3000
5.1.3 获取数据库连接池对象:通过工厂类来获取 DruidDataSourceFactory
5.1.4 获取连接:getConnection
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
public class DruidDemo {
public static void main(String[] args) throws Exception {
Properties pro=new Properties();
InputStream resourceAsStream = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(resourceAsStream);
DataSource ds = DruidDataSourceFactory.createDataSource(pro);
Connection connection = ds.getConnection();
System.out.println(connection);
}
}
5.2 定义工具类
5.2.1 定义一个类 JDBCUtils
5.2.2 提供静态代码块加载配置文件,初始化连接池对象
5.2.3 提供方法
①获取连接方法:通过数据库连接池获取连接
②释放资源
③获取连接池的方法
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class DruidJdbcUtils {
private static DataSource ds=null;
static {
Properties pro=new Properties();
InputStream resourceAsStream = DruidJdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
try {
pro.load(resourceAsStream);
} catch (IOException e) {
e.printStackTrace();
}
try {
ds= DruidDataSourceFactory.createDataSource(pro);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
public void close(Connection conn, Statement statement){
this.close(conn,statement,null);
}
public void close(Connection conn, Statement statement, ResultSet resultSet){
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public DataSource getDatasource(){
return ds;
}
}
Spring JDBC
* Spring框架对JDBC的简单封装。提供一个JDBC对象简化JDBC的开发
* 步骤:
1. 导入jar包
2. 创建JdbcTemplate对象。依赖于数据源DataSource
*JdbcTemplate template = new JdbcTemplate(ds);
3. 调用JdbcTemplate的方法来完成CRUD的操作
* update():执行DML语句。增、删、改语句
* queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value
* 注意:这个方法查询的结果集长度只能是1
* queryForList():查询结果将结果集封装为list集合
* 注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
* query():查询结果,将结果封装为JavaBean对象
* query的参数:RowMapper
* 一般我们使用BeanProperRowMapper实现类。可以完成数据到JavaBean的自动封装
* new BeanPropertyRowMapper<类型>(类型.class)
* queryForObject():查询结果,将结果封装为对象
* 一般用于聚合函数的查询