JDBC 超详细笔记
引言:
本文主要分享了有关JDBC的内容包括:JDBC的概述(思想和环境的搭建)、JDBC的核心6步、ResultSet结果集、SQL注入问题、Statement接口、PreparedStatement接口(案例)、登录案例、封装工具类、ORM、DAO、日期类型的封装、JDBC事务、连接池(Druid德鲁伊连接池)以及若干案例;
@[toc]
1. JBDC概述
JDBC(Java DataBase Connectivity):Java连接数据库,可以使用Java语言连接数据库完成CRUD操作;
- CRUD:指在做计算处理时的增加(Create)、读取查询(Retrieve)、更新(Update)和删除(Delete)几个单词的首字母简写;
1.1 JDBC核心思想
Java中定义了访问数据库的接口,可以为多种关系型数据库提供统一的访问方式;
由数据库厂商提供驱动实现类(Driver数据库驱动);
1.2 MySQL中JDBC驱动包
JDBC下载路径:https://dev.mysql.com/downloads/connector/
1.3 JDBC API
JDBC 是由多个接口和类进行功能实现;
1.4 环境的搭建
- 在项目下新建 lib 文件夹(New--->directory),用于存放 jar 文件;
- 将MySQL驱动文件mysql-connector-java-5.1.25-bin.jar 复制到项目的lib文件夹中;
- 选中lib文件夹 右键选择 add as library;
2. JDBC的开发六步
2.1 加载驱动
使用Class.forName("com.mysql.jdbc.Driver");手动加载字节码文件到JVM中
Class.forName("com.mysql.jdbc.Driver");
2. 2 连接数据库
通过DriverManager.getConnection(url,user,password);获得数据库连接对象
Connection connection = DriverManager.getConnection
("jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=utf8","root","root");
- URL(Uniform Resource Locator)统一资源定位符:由协议、IP、端口、SID(程序实例名称)组成
2.3 获取执行的SQL的对象
通过Connection对象获得Statement对象,用于对数据库进行通用访问的
功能:针对预计执行更新操作
- Statement createStatement() :创建一条 SQL 语句对象
Statement statement = connection.createStatement();
2.4 编写SQL语句并执行
编写SQL语句,并执行,接收执行后的结果
- int executeUpdate(String sql:静态sql) :DDL(不返回内容) ,DML(操作语句,返回具体的行数)
- 参数:SQL 语句
- 返回值:返回对数据库影响的行数
- ResultSet executeQuery(String sql):用于发送 DQL 语句,执行查询的操作。select
- 参数:SQL 语句
- 返回值:查询的结果集
String sql = "update stu set student_name = '张三' where student_id = '1004'";
int result = statement.executeUpdate(sql);
- 在编写DML语句时,要注意字符串参数的符号是单引号 '值'
- DML语句:增、删、改时,执行的结果是受影响行数(int类型);
- DQL语句:查询时,返回的是数据结果集(ResultSet结果集);
2.5 处理结果
接收并处理操作结果
if(result > 0){
System.out.println("成功!");
}else{
System.out.println("失败!");
}
- 受影响行数:逻辑判断,方法返回
- 查询结果集:迭代、依次获取
2.6 释放资源
遵循的是先开后关的原则,释放过程中用到的所有资源对象
statement.close();
connection.close();
2.7 增删改案例
综合核心六步,实现增删改
public static void main(String[] args) throws Exception {
//1.加载驱动 将驱动字节码文件加载到JVM中
Class.forName("com.mysql.jdbc.Driver");
//2.连接数据库
String url = "jdbc:mysql://localhost:3306/companydb?useUnicode=true&characterEncoding=utf8";//连接地址
String user = "root" ;
String password = "root";
Connection connection = DriverManager.getConnection(url,user,password);
//测试是否连接成功
System.out.println(connection);
//3.获取执行SQL的对象 Statement
Statement statement = connection.createStatement();
//4.编写SQL语句,并执行SQL语句
//增加
String sql1 = "INSERT INTO stu(student_id,student_name,sex,birthday,phone,GradeId) VALUES('1003','kaka','男','2001-06-01','123456189',1);";
//删除
String sql2 = "delete from stu where student_id = '1003'";
//修改
String sql3 = "update stu set student_name = '张三' where student_id = '1004'";
int result = statement.executeUpdate(sql3);
//5.处理结果
if(result > 0){
System.out.println("成功!");
}else{
System.out.println("失败!");
}
//6.释放资源 先开后关
statement.close();
connection.close();
}
}
3. ResultSet(结果集)
在执行查询SQL后,存放查询到的结果集数据;
3.1 接收结果集
ResultSet resultSet = statement.executeQuery(sql);
ResultSet executeQuery(String sql):用于发送 DQL 语句,执行查询的操作,select
- 参数:SQL 语句
- 返回值:查询的结果集
String sql = "select student_id,student_name,sex,birthday,phone,GradeId from stu";
ResultSet resultSet = statement.executeQuery(sql);
3.2 遍历ResultSet中的数据
ResultSet以表(Table)结构进行临时结果的存储,需要通过JDBC API将其中的数据进行依次获取
- boolean next():数据行指针,初始位置在第一行数据前,每调用一次boolean next()方法,ResultSet中指针向下移动一行,结果为true,表示当前行有数据;
- int /String ...getInt(int columnIndex) :获取当前列的编号对应的内容第一列就是1...
- int/String....getInt(String Stringcolumn):通过类的名称获取的信息
boolean next() throws SQLException;//判断resultSet结果集中下一行是否有数据
int getInt(int columnIndex) throws SQLException;//获得当前行的第N列的int值
int getInt(String columnLabel) throws SQLException;//获得当前行columnLabel列的int值
- 列的编号从1开始;
3.3 查询案例
3.3.1 根据列名进行查询
/**
* 方式一
* 根据列名
* JDBC查询数据库表的数据
*/
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class TestDQL {
public static void main(String[] args) throws Exception{
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获得连接
String url = "jdbc:mysql://localhost:3306/companydb?useUnicode = true&characterEncoding = utf8";
String user = "root";
String password = "root";
Connection connection = DriverManager.getConnection(url,user,password);
//3.获取执行的对象
Statement statement = connection.createStatement();
//4.编写SQL语句 查询
String sql = "select student_id,student_name,sex,birthday,phone,GradeId from stu";
ResultSet resultSet = statement.executeQuery(sql);
//5.处理结果
while(resultSet.next()){
//判断是否有下一行
//1.根据列名获取当前行的每一列数据
String student_id = resultSet.getString("student_id");
String student_name = resultSet.getString("student_name");
String sex = resultSet.getString("sex");
String birthday = resultSet.getString("birthday");
String phone = resultSet.getString("phone");
String gradeId = resultSet.getString("gradeId");
System.out.println(student_id+"\t"+student_name+"\t"+sex+"\t"+birthday+"\t"+phone+"\t"+gradeId);
}
//6.释放资源
resultSet.close();
statement.close();
connection.close();
}
}
3.3.2 根据列的下标进行查询
//方式二前面步骤如上:
//5.处理结果
while(resultSet.next()){
//判断是否有下一行
//1.根据列名获取当前行的每一列数据
String student_id = resultSet.getString(1);
String student_name = resultSet.getString(2);
String sex = resultSet.getString(3);
String birthday = resultSet.getString(4);
String phone = resultSet.getString(5);
String gradeId = resultSet.getString(6);
System.out.println(student_id+"\t"+student_name+"\t"+sex+"\t"+birthday+"\t"+phone+"\t"+gradeId);
}
3.4 常见的错误
- java.lang.ClassNotFoundException :找不到类(类名书写错误、没有导入jar包);
- com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException :与SQL语句相关的错误(表名列名书写错误、约束错误、插入的值是String类型,但是没有加单引号)建议:在客户端工具中测试sql语句后,再粘贴到代码中来;
- com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1003' for key 'PRIMARY' :主键值已存在,更改要插入的主键值;
- com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:Unknown column 'password' in :可能输入的值的类型不对,确定插入元素时,对应的值的类型是否正确;
4. SQL注入问题
当用户输入的数据中有SQL关键字或语法时,并且参与了SQL语句的编译,导致SQL语句编译后条件结果为true,一直得到正确的结果。称为SQL注入;
- 如:XXX‘ or 1 = 1;# 将后面部分注释
避免SQL注入:
由于编写的SQL语句,是在用户输入数据后,整合后再编译成SQL语句。所以为了避免SQL注入的问题,使SQL语句在用户输入数据前,SQL语句已经完成编译,成为了完整的SQL语句,再进行填充数据;
5. PreparedStatement接口
5.1 PreparedStatement
PreparedStatement 是 Statement 接口的子接口,继承于父接口中所有的方法,是一个预编译的 SQL 语句;
好处:
- prepareStatement()会先将 SQL 语句发送给数据库预编译。PreparedStatement 会引用着预编译后的结果。 可以多次传入不同的参数给 PreparedStatement 对象并执行。减少 SQL 编译次数,提高效率;
- 安全,避免SQL注入;
- 可以动态的填充数据,执行多个同构的SQL语句;
- 提高可读性;
5.2 接口方法
- PreparedStatement prepareStatement(String sql):指定预编译的 SQL 语句,SQL 语句中使用占位符? 创建一个语句对象;
- int executeUpdate() :执行 DML,增删改的操作,返回影响的行数;
- ResultSet executeQuery():执行 DQL,查询的操作,返回结果集;
5.2.1 参数标记
ResultSet executeQuery():操作DQL语句进行查询
//1.预编译SQL语句
PreparedStatement preparedStatement = connection.prepareStatement(sql);
- 应用PreparedStatement时,SQL字符串的参数都由?符号站位,被称为参数标记。在执行该SQL语句前,要为每个参数赋值;
5.2.2 动态参数绑定
preparedStatement.setXxx(下标,值):参数下标是从1开始,为指定占位符下标绑定值;
//2.为占位符下标赋值
preparedStatement.setString(1,username);
preparedStatement.setString(2,password);
5.3 PreparedStatement使用步骤
- 编写 SQL 语句,未知内容使用?占位:"SELECT * FROM user WHERE name=? AND password=?";
- )获得 PreparedStatement 对象;
- 设置实际参数:setXxx(占位符的位置, 真实的值);
- 执行参数化 SQL 语句;
- 关闭资源;
5.4 案例
public User select(int id){
connection = DBUtils.getConnection();
String sql = "select id,username,password,sex,email,address from user where id = ?;";
try {
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,id);
resultSet = preparedStatement.executeQuery();
while(resultSet.next()){
int id = resultSet.getInt("id");
String username = resultSet.getString("username");
String password = resultSet.getString("password");
String sex = resultSet.getString("sex");
String email = resultSet.getString("email");
String address = resultSet.getString("address");
User user = new User(id,username,password,sex,email,address);
return user;
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtils.closeAll(connection,preparedStatement,resultSet);
}
return null;
}
6. Statement和PreparedStatement的区别
Statement:
- 执行对象执行对应的sql语句(DDl,DQL,DML)
- DDL/DML:executeUpdate(String sql) --- >int
- DQL:executeQuery(String sql) ---->ResultSet 结果集
- 安全隐患:
- 在拼接sql语句,使用一些关键字和表中的字段进行拼接(SQL注入)
- 执行效率低
- 录入不存在用户名以及不存在密码依然可以登录成功
PreparedStatement:
- 获取预编译对象,会将参数化的sql发送给数据库
- 通过setXXX(参数1,参数2)给这些占位符进行赋值
- XXX:表示类型 :给id字段设置数据如:setInt(1,1)
- 参数1:当前预编译的sql语句中的第几个占位符
- 参数2:给当前这个占位符赋值的实际值是什么
- 预编译对象进行参数赋值
- 预编译对象.setString(1,"zhangsan")
- 预编译对象.setString(2,"123") ;
- 特点:
- 防止的SQL注入(更安全的)
- 执行效率高
7. 综合案例---登录
7.1 创建表并插入数据
CREATE TABLE `user`(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(20) NOT NULL,
`password` VARCHAR(20) NOT NULL,
phone VARCHAR(11)
)CHARSET = utf8;
INSERT INTO `user`(username, `password`,phone) VALUES ('kaka','123','12345678910');
INSERT INTO `user`(username, `password`,phone) VALUES ('tangtang','456',NULL);
SELECT * FROM `user`;
7.2 实现登录
/**
* 登录操作
* 通过控制台,用户输入用户名和密码;
* 用户输入的用户名和密码作为参数,编写查询SQL语句;
* 如果查询到用户,则用户存在,提示登录成功,反之,提示失败;
*/
import java.util.Scanner;
import java.sql.*;
public class TestSafeLogin {
public static void main(String[] args) throws Exception{
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名:");
String username = sc.next();
System.out.println("请输入密码:");
String password = sc.next();
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获得连接
String url = "jdbc:mysql://localhost:3306/companydb?useUnicode = true&characterEncoding = utf8";
Connection connection = DriverManager.getConnection(url,"root","root");
//3.获取执行的对象
String sql ="select * from user where username = ? and password = ?";
//预编译
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//为SQL语句赋值
preparedStatement.setString(1,username);
preparedStatement.setString(2,password);
//4.执行SQL语句
ResultSet resultSet = preparedStatement.executeQuery();
//5.处理结果
if(resultSet.next()){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
//6.释放资源
resultSet.close();
preparedStatement.close();
connection.close();
}
}
8. 封装工具类
8.1 jdbc.properties
- 在src目录下新建jdbc.properties文件
driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/db0707?useUnicode=true&characterEncoding=utf8
user = root
password = root
8.2 JDBCUtils.java
- 工具类的实现
public class JDBCUtils {
//定义成员
private static String url;
private static String user;
private static String password;
private static String driver;
static{
try {
Properties prop = new Properties();
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
URL urlPath = classLoader.getResource("jdbc.properties");
String path = urlPath.getPath();
prop.load(new FileReader(path));
url = prop.getProperty("url");
user = prop.getProperty("user");
password = prop.getProperty("password");
//加载驱动
Class.forName(prop.getProperty("driver"));
} catch (Exception e) {
e.printStackTrace();
}
}
//获取数据库连接对象
public static Connection getConnection(){
try {
Connection conn = DriverManager.getConnection(url, user, password);
return conn;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
//释放资源(DDL、DML)
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();
}
}
}
//针对DQL语句的关闭
public static void close(ResultSet rs,Statement stmt,Connection conn) {
if(rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt!=null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
9. ORM(Object Relational Mapping)
ORM(Object Relational Mapping)
从数据库查询到的结果集(ResultSet)在进行遍历时,逐行遍历,取出的都是零散的数据。在实际应用开发中,我们需要将零散的数据进行封装整理;
9.1 创建表
CREATE TABLE `user`(
id INT PRIMARY KEY,#主键
username VARCHAR(20) NOT NULL,
`password` VARCHAR(20) NOT NULL,#非空
sex CHAR(2),
email VARCHAR(50) NOT NULL,
address VARCHAR(20) NOT NULL
)CHARSET = utf8;
INSERT INTO `user` (id,username,`password`,sex,email,address)
VALUES (1001,'kaka','123','男','123456789@qq.com','陕西省');
9.2 封装工具类
/**
* 数据库工具类
* 1.获取连接 connection
* 2.释放资源
* 可跨平台方案
*/
import java.io.*;
import java.sql.*;
import java.util.Properties;
public class DBUtils{
//配置文件集合 永远不变
private static final Properties properties = new Properties();
static {
try {
//使用类自带的流
//首次使用工具类,触发类加载
InputStream is = DBUtils.class.getResourceAsStream("/db.properties");
//通过流将配置信息的内容分割成键值对
//将is流中的配置文件信息,加载到集合中
properties.load(is);
Class.forName(properties.getProperty("driver"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//获得连接
public static Connection getConnection(){
Connection connection = null;
try {
connection = DriverManager.getConnection(properties.getProperty("url"),properties.getProperty("username"),properties.getProperty("password"));
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
//释放资源
public static void closeAll(Connection connection, Statement statement, ResultSet resultSet) {
try {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
9.3 User类
public class User {
private int id;
private String username;
private String password;
private String sex;
private String email;
private String address;
public User(){
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", sex='" + sex + '\'' +
", email='" + email + '\'' +
", address='" + address + '\'' +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public User(int id, String username, String password, String sex, String email, String address) {
this.id = id;
this.username = username;
this.password = password;
this.sex = sex;
this.email = email;
this.address = address;
}
}
9.4 OrmSelect类
/**
* ORM查询
*/
import java.sql.*;
public class OrmSelect {
public static void main(String[] args) {
Connection connection = DBUtils.getConnection();
String sql = "select id,username,PASSWORD,sex,email,address from `user`;";
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
preparedStatement = connection.prepareStatement(sql);
resultSet = preparedStatement.executeQuery();
//拿到每一行数据
while (resultSet.next()) {
//拿到每一列的数据
User user = new User();
int id = resultSet.getInt("id");
String username = resultSet.getString("username");
String password = resultSet.getString("password");
String sex = resultSet.getString("sex");
String email = resultSet.getString("email");
String address = resultSet.getString("address");
//将零散的数据,封装在User对象里
user.setId(id);
user.setUsername(username);
user.setPassword(password);
user.setSex(sex);
user.setEmail(email);
user.setAddress(address);
System.out.println(user);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtils.closeAll(connection, preparedStatement, resultSet);
}
}
}
10. DAO(Data Access Object)
DAO(Data Access Object)数据访问对象:将所有对同一张表的操作都封装在一个XXXDaoImpl对象中、根据增删改查的不同功能,实现具体的方法(insert,update,delete,select,selectAll);
- 对于任何一张表中的数据进行操作时(增、删、改、查);应将对于一张表的所有操作统一封装在一个数据访问对象中为了实现重用;
10.1 创建表
CREATE TABLE employee(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(30),
sex VARCHAR(2),
salary DOUBLE
) CHARSET = utf8;
10.2 创建Employee类
public class Employee {
private int id;//工号
private String name;//名字
private String sex;//性别
private double salary ;//工资
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "employee [id=" + id + ", name=" + name + ", sex=" + sex + ", salary="
+ salary + "]";
}
public Employee() {
super();
// TODO Auto-generated constructor stub
}
public Employee(int id, String name, String sex, double salary) {
super();
this.id = id;
this.name = name;
this.sex = sex;
this.salary = salary;
}
}
10.3 封装工具类
见第7个板块
10.4 UserDaoImpl
/*
*对数据库中emp;oyee表的一系列操作(增删改查)
*实现增删改查
*/
public class UserDaoImpl {
private Connection conn = null;
private PreparedStatement stmt = null;
private ResultSet rs = null;
//增加
public int insert(Employee emp){
try {
//数据库连接对象
conn = JDBCUtils.getConnection();
//编写SQL语句
String sql = "insert into employee (id,name,sex,salary) values(?,?,?,?);";
//预编译对象
stmt = conn.prepareStatement(sql);
//执行更新
stmt.setInt(1, emp.getId());
stmt.setString(2, emp.getName());
stmt.setString(3, emp.getSex());
stmt.setDouble(4, emp.getSalary());
int i = stmt.executeUpdate();
return i;
} catch (Exception e) {
e.printStackTrace();
} finally{
JDBCUtils.close(stmt, conn);
}
return 0;
}
//删除
public int delete (int id){
conn = JDBCUtils.getConnection();
String sql = "delete from employee where id = ?";
try {
stmt = conn.prepareStatement(sql);
//获取id
stmt.setInt(1, id);
return stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtils.close(stmt, conn);
}
return 0;
}
//修改
public int update(Employee emp){
conn = JDBCUtils.getConnection();
String sql = "update employee set name = ?,sex = ?,salary = ? where id = ?";
try {
stmt = conn.prepareStatement(sql);
//执行更新
stmt.setString(1, emp.getName());
stmt.setString(2, emp.getSex());
stmt.setDouble(3, emp.getSalary());
stmt.setInt(4, emp.getId());
return stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtils.close(stmt, conn);
}
return 0;
}
//查询
public List<Employee> selectAll(){
conn = JDBCUtils.getConnection();
String sql = "select id,name,sex,salary from employee";
List<Employee> empList = new ArrayList<Employee>();
try {
stmt = conn.prepareStatement(sql);
rs = stmt.executeQuery();
while(rs.next()){
int id = rs.getInt("id");
String name = rs.getString("name");
String sex = rs.getString("sex");
double salary = rs.getDouble("salary");
Employee emp = new Employee(id, name, sex, salary);
//每封装完一个对象,添加到集合当中
empList.add(emp);
}
return empList;
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtils.close(stmt, conn);
}
return null;
}
}
10.5 测试类
public class JDBCTest {
public static void main(String[] args) {
//新增
UserDaoImpl udi = new UserDaoImpl();
Employee emp = new Employee(3,"wangwu","nv",4555);
int result = udi.insert(emp);
if(result > 0){
System.out.println("success");
}else{
System.out.println("defeat");
}
//删除
int result = udi.delete(3);
System.out.println(result);
//修改
Employee emp = new Employee(1,"kaka","m",12345);
int result = udi.update(emp);
System.out.println(result);
//查询
List<Employee> empList = udi.selectAll();
empList.forEach(System.out::println);
}
}
11. 日期类型
java.util.Date
java语言常规应用层面的日期类型;可以通过字符串创建对应的时间对象;无法直接通过JDBC插入数据库
java.sql.Date
不可以通过字符串创建对应的时间对象;只能通过毫秒值创建对象;可以直接通过JDBC插入数据库
sql赋util可以,util赋sql不行,因为sql是util的子类;
11.1 日期格式化工具
- SimpleDateFormat 日期格式化
//自定义一个时间
String str = "2020-02-02";
//日期转换将字符串转为 java.util.Date
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//将日期字符串转换成 util.Date类型
java.util.Date utilDate = sdf.parse(str);
System.out.println(utilDate);
11.2 日期工具类
/**
* 日期转换
* 字符串转UtilDate
* 字符串转SqlDate
* utilDate转成SqlDate
*/
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class DateUtils {
private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
//字符串转Util
public static java.util.Date strToUtilDate(String str) {
try {
return simpleDateFormat.parse(str);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
//字符串转sql(不常用)
public static java.sql.Date strToSqlDate(String str){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
try {
java.util.Date date = simpleDateFormat.parse(str);
return new java.sql.Date(date.getTime());
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
//util转sql
public static java.sql.Date utilToSql(java.util.Date date){
return new java.sql.Date(date.getTime());
}
}
11.3 测试类
public static void main(String[] args) throws ParseException{
//1.java.util.Date
// 当前系统时间
System.out.println(new java.util.Date());
//自定义一个时间
String str = "2020-02-02";
//日期转换将字符串转为 java.util.Date
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//将日期字符串转换成 util.Date类型
java.util.Date utilDate = sdf.parse(str);
System.out.println(utilDate);
//sql.Date 需要毫秒值,来构建一个日期
java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());
System.out.println(sqlDate);
java.util.Date date = DateUtils.strToUtilDate("2020-03-28");
System.out.println(date);
java.sql.Date date2 = DateUtils.utilToSql(date);
System.out.println(date2);
}
}
12. JDBC事务
使用JDBC操作事务,在对业务进行操作的时候,将业务操作使用事务进行管理,操作结果要么同时成功,要么同时失败;
void setAutoCommit(boolean autoCommit):
参数是 true 或 false 如果设置为 false,表示关闭自动提交,相当于开启事务
void commit():提交事务
void rollback():回滚事务
12.1 开发步骤
- 获取连接
- 开启事务
- 获取到 PreparedStatement
- 使用 PreparedStatement 执行两次更新操作
- 正常情况下提交事务
- 出现异常回滚事务
- 关闭资源
12.2 创建表
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
balance DOUBLE
);
-- 插入账户
INSERT INTO account (NAME , balance) VALUE ('zhangsan',1000);
INSERT INTO account (NAME , balance) VALUE ('lisi',1000);
12.3 加入事务处理
public class JDBCDemo {
public static void main(String[] args) {
Connection conn = null ;
PreparedStatement ps1 = null ;
PreparedStatement ps2 = null ;
try {
//获取数据库的连接对象
conn = JDBCUtils.getConnection() ;
//开启事务 //Mysql:中开启 start transaction ;
conn.setAutoCommit(false); //false开启收到提交 ,true自动提交
//准备sql语句
String sqlStr1 = "update account set balance = balance - ? where id = ?" ;
String sqlStr2 = "update account set balance = balance + ? where id = ?" ;
//使用连接对象获取预编译对象,给数据库发送sql进行预编译操作
ps1 = conn.prepareStatement(sqlStr1) ;
ps2 = conn.prepareStatement(sqlStr2) ;
//分别设置参数
ps1.setDouble(1, 500);
ps1.setInt(2, 1);
ps2.setDouble(1, 500);
ps2.setInt(2, 2);
//进行更新
int count1 = ps1.executeUpdate() ;
System.out.println(count1);
System.out.println(sqlStr1);
//模拟中间有问题
int x = 3 / 0 ; //程序问题了,程序结束
int count2 = ps2.executeUpdate() ;
System.out.println(count2);
System.out.println(sqlStr2);
//提交事务
conn.commit();
} catch (SQLException e) {
//回滚 //如果程序问题了,执行catch语句
if(conn!=null) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();
}finally {
JDBCUtils.close(ps1, conn);
JDBCUtils.close(ps2, null);
}
}
}
12.4 DBUtils封装事务控制
//开启事务
public static void begin(){
Connection connection = getConnection();
try {
connection.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
//提交事务
public static void commit(){
Connection connection = getConnection();
try {
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtils.closeAll(connection,null,null);
}
}
//回滚事务
public static void rollback(){
Connection connection = getConnection();
try {
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtils.closeAll(connection,null,null);
}
}
13.连接池
JDBC每次连接数据库,都要获得一个连接对象。每次创建一个连接对象,都是一个较大的资源,如果在连接量较大的场景下,会极大的浪费资源,容易内存溢出。
连接池就是一个容器,创建好数据库连接对象之后,将这些连接对象存储到容器(初始化)中,每次使用连接对象之后,而是将连接对象归还到连接池中,等待下一次利用;
13.1 c3p0连接池
Java中提供了一个接口DataSource,通过实现该接口,可以创建连接池
使用连接池:c3p0: 需要提供的对应的mysql的c3p0相关的jar包
导入:c3p0-0.9.5.2.jar核心jar包以及它相关的依赖jar包 mchange-commons-java-0.2.12.jar
13.2 Druid(德鲁伊)
Druid 是目前比较流行高性能的,分布式列存储
一、亚秒级查询
二、实时数据注入
三、可扩展的PB级存储
四、多环境部署
五、丰富的社区
13.2.1 Druid配置
- 创建druid.properties 配置文件
- 引入druid-1.0.9.jar包
- 需要借助工厂类DruidDataSourceFactory 创建具体的连接池
- 获取DataSouce:连接池对象(接口) 通过连接池获取数据库的连接
- Connection getConnection() throws SQLException;
13.2.2 database.properties 文件配置
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db0708?useUnicode=true&characterEncoding=utf8
username=root
password=root
#初始化连接
initialSize=10
#最大连接数量
maxActive=30
#最小空闲连接
minIdle=5
#超时等待时间以毫秒为单位
maxWait=5000
13.2.3 连接池工具类
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;
import javax.sql.DataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
/*
*将Druid连接池的获取通过工具类进行封装使用连接池创建连接对象(每次close()都会归还到连接池中),
*操作DDL,DML,DQL都一样
*/
public class JDBCUtils {
//获取数据库连接池
private static DataSource ds;
//提供静态代码块
//加载配置文件
static{
try{
//创建Properties集合类对象
Properties prop = new Properties();
//加载配置文件
InputStream inputStream = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
//加载
prop.load(inputStream);
inputStream.close();
//创建连接池对象
ds = DruidDataSourceFactory.createDataSource(prop);
} catch(IOException e){
e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return ds.getConnection() ;
}
//定义一个方法,获取存在的连接池
public static DataSource getDataSource() {
return ds ;
}
//释放资源
public static void close(Statement stmt,Connection conn) {
close(null,stmt,conn) ;
}
public static void close(ResultSet rs, Statement stmt, Connection conn) {
if(rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt!=null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
12.2.4 创建表
-- 创建账户表
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
balance DOUBLE
)CHARSET = utf8;
-- 插入账户
INSERT INTO account (NAME , balance) VALUE ('张三',1000);
INSERT INTO account (NAME , balance) VALUE ('李四',1000);
12.2.5 测试类
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.kaka.utils.JDBCUtils;
public class DruidTest {
public static void main(String[] args) {
Connection conn = null ;
PreparedStatement stmt = null ;
try {
//获取连接
conn = JDBCUtils.getConnection() ;
//准备sql :给account表中插入数据
String sql = "insert into account values(null,?,?)" ;
//获取预编译对象
stmt = conn.prepareStatement(sql) ;
//设置参数
stmt.setString(1, "王五");
stmt.setDouble(2, 3000);
//执行更新
int count = stmt.executeUpdate();
System.out.println("更新成功,影响了"+count);
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtils.close(stmt, conn);
}
}
}