1. JDBC目的:连接任何提供了JDBC驱动程序的数据库系统,提供统一接口。
2. JDBC 编写接口,mysql厂商开发接口实现。Java程序员通过调用接口,动态绑定厂商的接口实现。
3.JDBC的类和接口主要在java.sql和javax.sql中
4. JDBC程序编写步骤:
4.1 注册驱动:加载Driver类
jdbc:mysql://127.0.0.1:3306/db03
//等价于
jdbc:mysql://localhost:3306/db03
4.2 获取连接:得到Connection
4.3 执行增删改查:发送SQL给mysql执行
4.4 释放资源:关闭相关连接
5.获取连接的五种方式
public class JdbcConn {
@Test
//JUint单元测试
public void connect01() throws SQLException {
Driver driver = new Driver();
String url = "jdbc:mysql://localhost:3306/db03";
//将用户名和密码放入Properties
Properties properties = new Properties();
Object user = properties.setProperty("user", "root");
Object pwd = properties.setProperty("password", "xiaoyahuan1997");
Connection connect = driver.connect(url, properties);
System.out.println(connect);
}
//方式2
@Test
public void connect02() throws ClassNotFoundException, IllegalAccessException, InstantiationException, SQLException {
//使用反射加载
Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver)aClass.newInstance();
String url = "jdbc:mysql://localhost:3306/db03";
//将用户名和密码放入Properties
Properties properties = new Properties();
properties.setProperty("user", "root");
properties.setProperty("password", "xiaoyahuan1997");
Connection connect = driver.connect(url, properties);
System.out.println("方式2 = " + connect);
}
//方式3 使用DriverManager 替代Driver进行统一管理
@Test
public void connect03() throws ClassNotFoundException, IllegalAccessException, InstantiationException, SQLException {
Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
Driver driver = (Driver) aClass.newInstance();
String url = "jdbc:mysql://localhost:3306/db03";
String user = "root";
String password = "xiaoyahuan1997";
DriverManager.registerDriver(driver);
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println("third = " + connection);
}
//方式4 使用Class.forName 自动完成注册驱动,简化代码
//使用最多,推荐使用
@Test
public void connect04() throws ClassNotFoundException, SQLException {
//使用反射加载了Driver类
//在加载Driver类时,完成注册
/*
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
*/
//mysql驱动5.1.6无需Class.forName("com.mysql.jdbc.Driver");
//Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/db03";
String user = "root";
String password = "xiaoyahuan1997";
//不用手动注册驱动器
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println("方式4 = " + connection);
}
@Test
//方式5,使用配置文件
public void connect05() throws IOException, ClassNotFoundException, SQLException {
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
String user = properties.getProperty("user");
String pwd = properties.getProperty("password");
String url = properties.getProperty("url");
String driver = properties.getProperty("driver");
String sql_1 = "insert into actor values(3,'alam','男','1997-07-05 00:00:00',153)";
Class.forName(driver);
Connection connection = DriverManager.getConnection(url, user, pwd);
System.out.println("方式5 = " + connection);
Statement statement = connection.createStatement();
int i = statement.executeUpdate(sql_1);
statement.close();
connection.close();
}
}
6. ResultSet[结果集]
public class Resultset_ {
public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {
//注册驱动
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
String user = properties.getProperty("user");
String pwd = properties.getProperty("password");
String url = properties.getProperty("url");
String driver = properties.getProperty("driver");
Class.forName(driver);
//得到连接
Connection connection = DriverManager.getConnection(url, user, pwd);
//得到statement
Statement statement = connection.createStatement();
//组织Sql
String sql = "select id, name, sex, borndate from actor";
//返回一个结果集,resultSet是一个接口,mysql厂商实现了这个接口
ResultSet resultSet = statement.executeQuery(sql);
//使用while取出数据
while (resultSet.next()) {
int id = resultSet.getInt(1);//获取该行的第一列数据
String name = resultSet.getString(2);
String sex = resultSet.getString(3);
Date date = resultSet.getDate(4);
System.out.println(id + "\t" + name + "\t" + sex + "\t" + date);
}
resultSet.close();
statement.close();
connection.close();
}
}
注:statement用于执行静态SQL语句并返回其生成的结果的对象。
7. SQL注入
7.1 建立连接后,需要对数据库进行访问,执行命名或是SQL语句,一般不使用Statement,因为存在SQL注入的风险。
PreparedStatement[预处理]
CallableStatement[存储过程]
7.2 SQL注入:恶意攻击数据库的一种方式,SQL注入可通过特殊符号的输入改变SQL语句的功能从而实现破坏数据库或访问本没有权限的信息。用PreparedStatement取代Statement可以防范SQL注入。
8.预处理查询PreparedStatement()
8.1 PreparedStatement()是Statement()的子接口
优势:不再使用+拼接sql语句,减少语法错误,且有效解决sql注入
预处理,大大减少编译次数
8.2 调用executeQuery(),返回ResultSet对象
8.3 调用executeUpdate(),执行增删改
8.4 代码实例
public class PreparedStatement_ {
public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {
Scanner scanner = new Scanner(System.in);
System.out.println("Please input the name of user: ");
String admin_name = scanner.nextLine();
//scanner.next()以空格为结束符,scanner.nextLine()以回车为结束符
System.out.println("Please input the password of user: ");
String admin_pwd = scanner.nextLine();
//注册驱动
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
String user = properties.getProperty("user");
String pwd = properties.getProperty("password");
String url = properties.getProperty("url");
String driver = properties.getProperty("driver");
Class.forName(driver);
//得到连接
Connection connection = DriverManager.getConnection(url, user, pwd);
//PreparedStatement
//3.1 组织sql,sql语句的?相当于占位符
String sql = "select name, pwd from admin where name= ? and pwd =?";
//3.2 得到preparedstatement,是一个实现了PreparedStatement接口的对象
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//3.3 通过setXXX()函数给?赋值,问好的下标从1开始
preparedStatement.setString(1, admin_name);
preparedStatement.setString(2, admin_pwd);
//执行select语句,此处参数不需要sql,因为已经通过set()函数赋过值了
ResultSet resultSet = preparedStatement.executeQuery();
//使用while取出数据
if (resultSet.next()) {
System.out.println("Log on successed!");
} else {
System.out.println("Log on failed");
}
//
resultSet.close();
preparedStatement.close();
connection.close();
}
}
9. JDBC API
9.1 DriverManager //驱动管理类
getconnection(url, user, pwd)
9.2 Connection接口
creatStatement //创建Statement对象
preparedStatement(sql) //生成预处理对象
9.3 Statement接口
executeUpdate(sql) //执行dml语句,返回影响的行数
executeQuery(sql) //执行查询,返回ResultSet()对象
execute(sql) //执行任意的sql,返回布尔值
9.4 PreparedStatement接口
executeUpdate(sql) //执行dml语句
executeQuery(sql) //执行查询,返回ResultSet
execute() //执行任意sql,返回布尔
setXxx(占位索引符,占位符的值) //解决SQL注入
setObject(占位索引符,占位符的值)
9.5 ResultSet(结果集)
next() //向下移动一行,如果没有下一行,则返回false
previous() //向上移动一行
getXxx(列的索引 | 列名)
getObject(列的索引 | 列名) //返回对应列的值,接受类型为Object
10. JDBCUtils //完成mysql的连接和关闭
public class JDBCUtils {
//只需一份做成静态
private static String user;
private static String password;
private static String url;
private static String driver;
//static 代码块初始化
static {
Properties properties = new Properties();
try {
properties.load(new FileInputStream("src\\mysql.properties"));
user = properties.getProperty("user");
password = properties.getProperty("password");
url = properties.getProperty("url");
driver = properties.getProperty("driver");
} catch (IOException e) {
//将编译异常转成运行异常
//这时调用者可以选择捕获或者默认处理!
throw new RuntimeException(e);
//e.printStackTrace();
}
}
public static Connection getConnection() {
try {
return DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static void close(ResultSet set, Statement statement, Connection connection) {
try {
if(set != null) {
set.close();
}
if(statement != null) {
statement.close();
}
if(connection != null) {
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
11.JDBC 事务
11.1 介绍
11.1.1 当一个Connection对象创建时,默认情况是自动提交事务,每次执行一个SQL语句,如果执行成功,就会向数据库自动提交,且不能回滚。
11.1.2 调用Connection的setAutoCommit(false)可以取消自动提交事务
11.1.3 在所有SQL语句都成功执行后,调用connnection.commit()方法提交事务
11.1.4 在其中某操作异常时,调用connection.rollback(),回滚事务,可以设置回滚点,默认回滚到事务开始的状态
connection.rollback();
connection.rollback(Savepoint savepoint);
12. 批处理
用于成批插入或更新记录。
如果需要批处理,则在url中需加上后缀"?rewriteBatchedStatements=true"
处理语句包括:
addBatch()
executeBatch()
clearBatch()
public class Batch_ {
//
@Test
public void batch() throws SQLException {
Connection connection = JDBCUtils.getConnection();
String sql = "insert into admin2 values(null, ?, ?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
for(int i=0; i<5000; i++) {
preparedStatement.setString(1, "Jack" + i);
preparedStatement.setString(2, "666");
preparedStatement.addBatch();
if((i + 1) % 1000 == 0) {
preparedStatement.executeBatch();
preparedStatement.clearBatch();
}
}
}
}
addBatch()其实是将SQL语句放入了ArrayList中。减少了运行次数和编译次数,因而效率提高。
13. 数据库连接池
传统连接数据库的方式不能控制创建的连接数量,如连接过多,也可能导致内存泄漏,MySQL崩溃。
为了解决上述问题,可采用数据库连接池技术。
13.1 预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,从连接池取出一个,使用完毕再放入。
13.2 数据库连接池负责分配、管理和释放数据库连接,增强了数据库连接的可复用性。
13.3 当请求连接太多时,这些请求被放入等待队列。
13.4 数据库连接池种类:
C3p0:稳定性好。
Druid(德鲁伊):阿里提供的数据库连接池。
14. Druid数据库连接池
速度快,目前最好用的Java数据库连接池。
Druid数据库连接池工具类(负责连接和断开)
15. Apache - DBUtils
问题提出:关闭connection后,resultSet结果集无法使用
resultSet不利于数据管理,只能用一次
使用返回信息也不方便
15.1 用类的属性表示表的列名,这种类被称为JavaBean
将结果集记录封装到ArrayList<JavaBean>中,一个JavaBean对象对应一条表记录,JavaBean对象放入到ArrayList集合中。
Q:这样内存岂不是会导致内存消耗巨高?