文章目录
一.JDBC的概述
1.JDBC的概念
JDBC ( Java DataBaseConnectivity java数据库连接)是一种用于执行SQL语句的JavaAPI,可以为多种关系型数据库提供统一访问,它是由一组用Java语言编写的类和接口组成的。
2.JDBC的本质
其实就是java官方提供的一套规范(接口)。用于帮助开发人员快速实现不同关系型数据库的连接!、
接口都有调用者和实现者。
面向接口编程、面向接口写实现类,这都属于面向接口编程
为什么SUN制定一套JDBC接口呢?
因为每个数据库的底层实现原理都不一样
每一个数据库产品都有自己独特的实现原理
各个数据库下的xxx.jar包下 有许多的.class文件,都是对JDBC接口的实现
3.JDBC编程六步
第一步:注册驱动(作用:告诉java程序,即将要连接的是哪个品牌的数据库)
第二步:获取连接(表示JVM的进程和数据库之间的进程的通道打开了)
第三步:获取操作库操作对象(专门执行sql语句的对象)
第四步:执行SQL语句
第五步:处理查询结果集(只有当第四步执行的是SELECT语句时,才会有第五步查询结果集)
第六步:释放资源(使用完资源一定要关闭资源,java和数据库都属于进程间的通信。开启之后一定要关闭)
二.JDBC编程六步具体操作
说明:localhost和127.0.0.1都是本机IP地址
public class JDBCTest {
public static void main(String[] args) {
Statement stmt = null;
Connection conn = null;
try {
//1.注册驱动
// DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());//匿名对象方式
//oracle驱动:
// Driver driver = new oracle.jdbc.driver.OracleDriver();
Driver driver = new com.mysql.cj.jdbc.Driver();
DriverManager.registerDriver(driver);
//2.获取连接
// 协议 IP地址 端口号 数据库实例名
String url = "jdbc:mysql://127.0.0.1:3306/atguigudb";
String name = "root";
String password = "qnmrbnmkfj666";
conn = DriverManager.getConnection(url, name, password);
System.out.println("数据库连接对象=" + conn);
//3.获取数据库的操作对象(Statement专门执行SQL语句)
stmt = conn.createStatement();
//4.执行sql
//专门执行DML语句(insert delete update)
String sql = "INSERT INTO myemp1 VALUES (1004,'lsls','2005-06-29',10000) ";
//返回值是 影响数据库表中的记录数
int count = stmt.executeUpdate(sql);
System.out.println(count == 1 ? "保存成功" : "保存失败");
//5.查询结果集
} catch (SQLException e) {
e.printStackTrace();
} finally {
//6.释放资源
//为了保证资源一定释放,在finally语句块中关闭资源
//并且要从小到大依次关闭
if(stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
在java中编写SQL语句时,不能加分号,否则报错
注册驱动的方式二:利用反射机制
相当于加载驱动,而并非建立驱动
//1.加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取数据库连接
String url = "jdbc:mysql://127.0.0.1:3306/atguigudb";
String name = "root";
String password = "qnmrbnmkfj666";
conn = DriverManager.getConnection(url, name, password);
//3.获取数据库对象
stmt = conn.createStatement();
//4.执行SQL语句
String sql = "DELETE FROM myemp1 WHERE id = 1005";
int count = stmt.executeUpdate(sql);
System.out.println(count == 1 ? "保存成功" : "保存失败");
方式三:通过读取配置文件获取连接
/**
* 将数据库连接需要的四个基本信息声明在配置文件中,通过读取配置文件方式获取连接
*
*/
public class JDBCTest3 {
public static void main(String[] args) throws Exception{
//1.读取配置文件中的四个基本信息
//系统类加载器
InputStream is = JDBCTest3.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties pros = new Properties();
pros.load(is);
String user = pros.getProperty("user");
String url = pros.getProperty("url");
String password = pros.getProperty("password");
String dirverClass = pros.getProperty("dirverClass");
//2.加载驱动
Class.forName(dirverClass);
//3.获取连接
Connection conn = DriverManager.getConnection(url,user,password);
System.out.println(conn);
}
}
方法四(最终版本):
public class SqlConnect {
public static void main(String[] args) {
Connection conn = null;
Statement stat = null;
try {
//使用资源绑定器读取属性文件
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
String user = bundle.getString("user");
String driverClass = bundle.getString("driverClass");
String password = bundle.getString("password");
String url = bundle.getString("url");
//1.创建驱动
Class.forName(driverClass);
//2.建立数据库连接
conn = DriverManager.getConnection(url,user,password);
//3.建立数据库操作对象
stat = conn.createStatement();
//4.执行sql语句
String sql = "INSERT INTO myemp1(id) VALUES (1005)";
int count = stat.executeUpdate(sql);
System.out.println(count == 1 ? "增加成功" : "增加失败");
//5.查询结果集
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
//6.关闭流
if(stat != null){
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
java.util包下提供了一个资源绑定器,便于获取属性配置文件中的内容
使用以下这种方式的时候,属性配置文件xxx.properties必须放在类路径下。
方法四好处:
- 实现了数据和代码的分离,实现了解耦
- 如果需要修改配置文件信息,可以避免程序重新打包
三.遍历结果集
String sql = "SELECT id,name,hire_date,salary AS sal FROM myemp1";
//专门执行查询语句
ResultSet rs = stat.executeQuery(sql);
while(rs.next()){
//getSting不管数据库中的数据是什么类型,全部转换为String类型
//除了可以以String类型取出外,还可以以特定的类型去输出。但是要按照实际
int id = rs.getInt(1);//1代表第一列
String name = rs.getString(2);//2代表第二列
String hire_date = rs.getString("hire_date");//这里也可以用列名代替
Double salary = rs.getDouble("sal");//如果查询中修改了列名,这里也要相应改变
//若是数值型数据,则可以直接参与运算
System.out.println(id+","+name+","+hire_date+","+(salary + 100));
}
四.SQL注入
1.什么叫SQL注入?
SQL注入是网站存在最多也是最简单的漏洞,主要原因是程序员在开发用户和数据库交互的系统时没有对用户输入的字符串进行过滤,转义,限制或处理不严谨,导致用户可以通过输入精心构造的字符串去非法获取到数据库中的数据。
2.解决方法:
Statement对象用于执行静态SQL语句并返回其生成的结果的对象,但是其在执行SQL语句的的时候存在SQL注入风险,所以开发中选择PrepareStatement(预编译数据库操作对象)来代替Statement
实质就是让用户提供的信息数据不参与编译,即使提供的信息含有SQL语句的关键字,没有编译 也是不起作用的
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
java.sql.ResultSet rs = null;
try {
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
String user = bundle.getString("user");
String driverClass = bundle.getString("driverClass");
String password = bundle.getString("password");
String url = bundle.getString("url");
Class.forName(driverClass);
conn = DriverManager.getConnection(url,user,password);
//sql语句需要在获取数据库操作对象上面执行
String sql = "SELECT * FROM myemp1 WHERE user = ? AND password = ?";//数据要改为?,一个?代表一个占位符
//获取预编译的数据库操作对象
ps = conn.prepareStatement(sql);
//给占位符?传值(第一个问号下标是1,第二个问号下标是2,jdbc中下标从1开始)
ps.setString(1,user);
ps.setString(1,password);
//专门执行查询语句
rs = ps.executeQuery();//不需要传参数了
while(rs.next()){
//getSting不管数据库中的数据是什么类型,全部转换为String类型
//除了可以以String类型取出外,还可以以特定的类型去输出。但是要按照实际
int id = rs.getInt(1);//1代表第一列
String name = rs.getString(2);//2代表第二列
String hire_date = rs.getString("hire_date");//这里也可以用列名代替
Double salary = rs.getDouble("sal");//如果查询中修改了列名,这里也要相应改变
//若是数值型数据,则可以直接参与运算
System.out.println(id+","+name+","+hire_date+","+(salary + 100));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if(ps != null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
3.Statement和PrepareStatement的区别:
- Statement是编译一次,执行一次
- PrepareStatement是编译一次,可重复执行n此,所以效率较高
- PrepareStatement会在编译阶段做类的安全检查
- 凡是业务方面要求是需要进行sql语句拼接的,必须使用Statement
第四点具体比较代码如下:
public class StatementTest {
@Test
public void PrepareStatementTest() throws Exception{
/**
* PrepareStatement执行代码演示
* 报SQLSyntaxErrorException异常
*/
//用户在控制台输入desc为降序,输入asc为升序
Scanner scan = new Scanner(System.in);
System.out.println("输入desc为降序,输入asc为升序");
String keyWords = scan.nextLine();
//1.创建驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取数据库连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/atguigudb","root","qnmrbnmkfj666");
//3.获取预处理数据库操作对象
String sql = "SELECT id FROM myemp1 ORDER BY id ?";
PreparedStatement ps = conn.prepareStatement(sql);
//传入数据
ps.setString(1,keyWords);
//4.执行sql语句
ResultSet rs = ps.executeQuery();
//5.遍历结果集
while(rs.next()){
System.out.println(rs.getString("id"));
}
//6.关闭资源
rs.close();
ps.close();
conn.close();
}
public static void main(String[] args) throws Exception{
Scanner scan = new Scanner(System.in);
System.out.println("输入desc为降序,输入asc为升序");
String keyWords = scan.nextLine();
//1.创建驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.建立连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/atguigudb","root","qnmrbnmkfj666");
//3.创建数据库操作对象
Statement stat = conn.createStatement();
String sql = "SELECT id FROM myemp1 ORDER BY id " + keyWords;
//4.执行sql语句
ResultSet rs = stat.executeQuery(sql);
//5.遍历结果集
while(rs.next()){
System.out.println(rs.getString("id"));
}
//6.关闭资源
rs.close();
stat.close();
conn.close();
}
}
五.自定义JDBC工具类
1.具体代码
/**
* JDBC工具类,简化JDBC编程
*
*
* @author: ccw
* @date: 2022/5/16 23:30
*/
public class DBUtil {
/**
* 工具类中构造方法一般都是私有的。
* 因为工具类当中的方法都是静态的,不需要new对象,直接采用类名调用
*/
private DBUtil(){}
//创建驱动只需要执行一次,需要创建静态代码块
//静态代码块在类加载中执行,并且只执行一次
static {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接对象
*
* @return: 连接对象
* @author: ccw
* @date: 2022/5/16 23:42
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection("jdbc:mysql://localhost:3306/atguigudb",
"root","qnmrbnmkfj666");
}
/**
* 关闭资源
*
* @param conn 连接对象
* @param ps 数据库操作对象
* @param rs 结果集
*
* @author: ccw
* @date: 2022/5/16 23:44
*/
public static void close(Connection conn, Statement ps, ResultSet rs){
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(ps != null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
2.工具类的使用
/**
* 使用DBUtil中的方法
* 进行模糊查询
*
* @author: ccw
* @date: 2022/5/17 0:05
*/
public class UtilTest {
public static void main(String[] args){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection();
String sql = "SELECT * FROM myemp1 WHERE name LIKE ?";
ps = conn.prepareStatement(sql);
ps.setString(1,"_o%");
rs = ps.executeQuery();
while(rs.next()){
System.out.println(rs.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(conn,ps,rs);
}
}
}