JDBC基础(1)
一、概述
1.1、什么是JDBC
JDBC(Java Database Connectivity,Java数据库连接) 是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问。
简单说就是用Java语言来操作数据库。原来我们操作数据库是在控制台使用SQL语句来操作数据库,JDBC是用Java语言向数据库发送SQL语句。
1.2、JDBC原理
二、JDBC入门
2.1、准备工作
2.1.1、建库建表
2.1.2、新建项目
1、新建Java项目;
2、在项目下新建lib目录;
3、将MySQL驱动jar包拷贝到lib目录下;
4、选中lib目录右键Add as Library -- 单击OK
2.2、建立连接
2.2.1、准备四大参数
2.2.2、加载驱动
例:
//加载驱动 Class.forName(driverName);
//建立连接 Connection conn = DriverManager.getConnection(url, username,password);
System.out.println(conn);
2.3、获取发送SQL的对象
//先准备好SQL语句 String sql = "";
//创建Statement Statement statement = conn.createStatement();
//发送SQL语句 增删改--executeUpdate(),返回受影响的行数 查--executeQuery(),返回结果集
int result = statement.executeUpdate(sql);
System.out.println("result = " + result);
//关闭 -- 后打开的先关闭
statement.close();
conn.close();
2.4、入门案例_查询_处理结果集
这里可见代码及其注释:
package day35;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;public class TestSelect {public static void main(String[] args) throws Exception{//四大参数String driverName = "com.mysql.jdbc.Driver";String url = "jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false";String user = "root";String password = "123456";//SQLString sql = "select * from 'tb_stu'";//加载驱动Class.forName(driverName);//建立连接Connection conn = DriverManager.getConnection(url, user, password);//获取StatementStatement statement = conn.createStatement();//发送SQLResultSet rSet = statement.executeQuery(sql);//处理结果 next()判断结果集中是否还有内容while (rSet.next()) {//列的标识从1开始int sid = rSet.getInt(1);String sname = rSet.getString(2);String sage = rSet.getString(3);String sgender = rSet.getString(4);//int sid = rSet.getInt("sid"); 也可这样System.out.println(sid + "-" + sname + "-" + sage + "-" + sgender);}//关闭 先进的后关闭rSet.close();statement.close();conn.close();}
}
三、PreparedStatement
3.1、SQL注入
3.1.1、什么是SQL注入
package day35;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;public class TestSelect {public static void main(String[] args) throws Exception{//四大参数String driverName = "com.mysql.jdbc.Driver";String url = "jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false";String username = "root";String password = "123456";//假设用户输入的数据String uname = "Peter' OR 1=1 AND `password`='a";//本来不对,但1=1永远对,即为SQL注入,是要处理的!!!!!!!!!!!!!!!!String pwd = "123";//SQLString sql = "select * from 'user' WHERE 'username'='" + username + "' AND 'password'='" + pwd + "'" ;//加载驱动Class.forName(driverName);//建立连接Connection conn = DriverManager.getConnection(url, username, password);//获取StatementStatement statement = conn.createStatement();//发送SQLResultSet rSet = statement.executeQuery(sql);//处理结果 next()判断结果集中是否还有内容if (rSet.next()) {System.out.println("登录成功....");}else{System.out.println("登录失败!!!");}//关闭 先进的后关闭rSet.close();statement.close();conn.close();}
}
3.1.2、如何避免SQL注入
由于编写的SQL语句是在用户输入数据,整合后再进行编译。所以为了避免SQL注入的问题,我们要使SQL语句在用户输入数据前就进行编译成完整的SQL语句,再进行填充数据。
使用PreparedStatement.
3.2、PreparedStatement使用
PreparedStatement继承了Statement接口,执行SQL语句的方法无异。
作用:
预编译SQL语句,效率高。
安全,避免SQL注入。
可以动态的填充数据,执行多个同构的SQL语句。
3.3、解决SQL注入
package day36;import java.sql.*;
//这个版面是重要的,需要背过的!!
public class TestSelect {public static void main(String[] args) throws Exception{//四大参数String driverName = "com.mysql.jdbc.Driver";String url = "jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false";String username = "root";String password = "123456";//假设用户输入的数据String uname = "Peter' OR 1=1 AND `password`='a";//本来不对,但1=1永远对,即为SQL注入,是要处理的!!!!!!!!!!!!!!!!String pwd = "123";//SQLString sql = "select * from 'user' WHERE 'username'=? AND 'password'=? " ;//建立连接Connection conn = DriverManager.getConnection(url, username, password);//获取PreparedStatementPreparedStatement statement = conn.prepareStatement(sql);//设置参数,注意:?的索引从1开始statement.setString(1, uname);statement.setString(2, pwd);//发送SQL 增删改-executeUpdate 查-executeQueeryResultSet resultSet = statement.executeQuery();//处理结果if(resultSet.next()){System.out.println("登录成功");}else{System.out.println("登录失败");}//关闭资源resultSet.close();statement.close();conn.close();}
}
把uanme改成Peter即可登录成功。
3.4、PreparedStatement_添加
package day36;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;public class TestInsert {public static void main(String[] args) throws Exception {//四大参数String driverName = "com.mysql.jdbc.Driver";String url = "jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false";String username = "root";String password = "123456";//SQLString sql = "INSERT INTO 'tb_stu'('sname', 'sage', 'sgender') VALUES (?,?,?)";//加载驱动Class.forName(driverName);//建立连接Connection conn = DriverManager.getConnection(url, username, password);//获取PreparedStatementPreparedStatement statement = conn.prepareStatement(sql);//设置参数statement.setObject(1,"zhangsan");statement.setObject(2,20);statement.setObject(3,"male");//发送SQLint result = statement.executeUpdate();//处理结果System.out.println(result);//关闭资源statement.close();conn.close();}
}
只需要改SQL语句和设置参数
3.5、PreparedStatement_查询
package day36;import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;public class TestSelect1 {public static void main(String[] args) throws Exception {//四大参数String driverName = "com.mysql.jdbc.Driver";String url = "jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false";String username = "root";String password = "123456";//根据性别查询学生String sql = "SELECT * FROM 'tb_stu' WHERE 'sgender'=?";//加载驱动Class.forName(driverName);//获取连接Connection conn = DriverManager.getConnection(url, username, password);//获取PreparedStatementPreparedStatement statement = conn.prepareStatement(sql);//设置参数 对应SQL语句的,SQL语句没问号时可以没有statement.setObject(1,"male");//发送SQLResultSet resultSet = statement.executeQuery();//处理结果while (resultSet.next()) {Integer sid = resultSet.getInt("sid");String sname = resultSet.getString("sname");int sage = resultSet.getInt("sage");String sgender = resultSet.getString("sgender");System.out.println(sid + " " + sname + " " + sage + " " + sgender);}//关闭资源resultSet.close();statement.close();conn.close();}
}
修改删除省。 。。
4、封装工具类
资源包配置文件:
工具类:
package utils;import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;//工具类 static Arrays Collections
public class JdbcUtil {private static String driverName;private static String url;private static String username;private static String password; static {try {Properties prop = new Properties();//加载配置文件prop.load(new FileInputStream("jdbc.properties"));//初始化四大参数driverName = prop.getProperty("jdbc.driverName");url = prop.getProperty("jdbc.url");username = prop.getProperty("jdbc.username");password = prop.getProperty("jdbc.password");//加载驱动Class.forName(driverName);} catch (IOException e) {throw new RuntimeException(e);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}}//获取连接public static Connection getConnection() throws SQLException {Connection conn = DriverManager.getConnection(url, username, password);return conn;}//关闭资源public static void closeAll(Connection conn, PreparedStatement statement, ResultSet rSet) throws Exception{if(rSet != null){rSet.close();}if(statement != null){statement.close();}if(conn != null){conn.close();}}
}
测试类:
package test03;import utils.JdbcUtil;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class TestSelect {public static void main(String[] args) throws SQLException {String sql = "SELECT * FROM 'tb_stu' WHERE 'sage'=?";//获取连接Connection conn = JdbcUtil.getConnection();//获取PreparedStatementPreparedStatement statement = conn.prepareStatement(sql);//设置参数statement.setObject(1, 20);//发送SQLResultSet rs = statement.executeQuery();//处理结果while (rs.next()) {int sid = rs.getInt("sid");String sname = rs.getString("sname");int sage = rs.getInt("sage");String sgender = rs.getString("sgender");System.out.println(sid + "\t" + sname + "\t" + sage + "\t" + sgender);}}
}
5、连接池介绍
例子:Druid连接池
Druid是阿里巴巴开源的一个数据源,主要用于java数据库连接池,相比spring推荐的DBCP和hibernate推荐的C3P0,此连接池比较占优势。
准备工作:导入lib等包
使用:
5.1、连接池_工具类
资源包配置文件:
连接池工具类:
package utils;import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;//工具类 static Arrays Collections
public class JdbcUtil {private static DataSource dataSource;static {try{Properties prop = new Properties();//加载配置文件InputStream in = JdbcUtil.class.getResourceAsStream("/jdbc.properties");prop.load(in);//创建连接池dataSource = DruidDataSourceFactory.createDataSource(prop);}catch(Exception e){e.printStackTrace();}}public static Connection getConnection() throws SQLException {return dataSource.getConnection();}public static void closeAll(Connection conn, PreparedStatement statement, ResultSet resultSet) throws SQLException{if(resultSet != null){resultSet.close();}if(statement != null){statement.close();}if(conn != null){conn.close();}}
}
测试类:
import utils.JdbcUtil;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class TestSelect {public static void main(String[] args) throws SQLException {//String sql = "SELECT * FROM 'tb_stu' WHERE 'sage'=?";//获取连接Connection connection = JdbcUtil.getConnection();//获取PreparedStatementPreparedStatement statement = connection.prepareStatement("SELECT * FROM 'tb_stu' WHERE 'sage'=?");//设置参数statement.setObject(1, 5);//发送SQLResultSet rs = statement.executeQuery();//处理结果while (rs.next()) {int sid = rs.getInt("sid");String sname = rs.getString("sname");int sage = rs.getInt("sage");String sgender = rs.getString("sgender");System.out.println(sid + "\t" + sname + "\t" + sage + "\t" + sgender);}//关闭资源JdbcUtil.closeAll(connection, statement, rs);}
}
6、三层架构
表示层(View)
以项目设计举例
7、DBUtils
是对JDBC的简单封装,但是它还是被很多公司使用。
主要功能:用来操作数据库,简化JDBC的操作。
在使用的时候要和数据库连接池、MySQL的jar配合使用。
7.1、主要类与方法
QueryRunner 执行sql语句的类
创建QueryRunner
构造器:QueryRunner(),在事务里面使用。
构造器:QueryRunner(连接池对象)
update():执行INSERT、UPDATE、DELETE
query():执行SELECT
且还有BeanListHandler(多行的)接口_实体类注意事项,BeanHandler(单行)
此构造器需要一个Class类型的参数,用来把一些指定结果转换成指定类型的javaBean对象
这里举例:
@Test
public void test04() throws SQLException{
String sql = "SELECT * FROM 'tb_stu' WHERE 'age'>?";
Object[] params = {10};
QueryRunner qr = new QueryRunner(JdbcUtil.getDataSource());
List<Student> studentList = qr.query(sql, new BeanListHandler<student>(Student.class), params);
studentList.stream()
.forEach(System.out::println);
}
}
此外还有MapListHandler(多行),MapHandler(单行),同理:
//其他代码同上
List<Map<String, Object>> list = qr.query(sql, new MapListHandler(), params);
//List<Map<String, Object>> list = qr.query(sql, new MapHandler(), params);
最后还有ScalarHandler(单行单列):通常用于select count(*) from t_stu语句!结果集是单行单列的!它返回一个Object聚合函数。
@Test
public void test08() throws SQLException{
String sql = "SELECT COUNT(1) FROM 'tb_stu'";
QueryRunner qr = new QueryRunner(JdbcUtil.getDataSource());
Long count = qr.query(sql, new ScalarHandler<long>());
System.out.println(count);
}
}
8、事务
8.1、
MYSQL - TPL
1、事务处理的SQL语句 见mysql基础
2、常见的面试题 背过
Java处理事务 - 在Service层处理事务,不能在Dao层处理事务
1、在JDBC中怎么处理事务 - 方法
2、在dbutils怎么处理事务 - JdbcUtil工具类
8.2、关于事务
8.1、什么是事务?
一个操作序列,这些操作序列要么都执行,要么都不执行,它是一个不可分割的工作单位。
事务要处理的问题,把多个对数据库的操作绑定成一个事务,要么都成功,要么都失败。
8.2、MySQL中处理事务
MySQL中处理事务涉及三个操作:
开启事务 START TRANSACTION;
中间有多个操作 delete update add select 等等
提交事务 COMMIT;
回滚 ROLLBACK;
8.3、事务原理
数据库会为每一个客户端都设立一个空间独立的缓存区(回滚段),一个事务中所有的增删改语句的执行结果都会缓存在回滚段中,只有当事务中所有SQL语句均正常结束(COMMIT),才会将回滚段中的数据同步到数据库。否则无论因为哪种原因失败,整个事务将回滚(ROLLBACK).
8.4、事务特性
原子性 一致性 隔离性 持久性
8.5 事务隔离级别
8.5.1、事务并发读问题
数据被b读取后跑了,之后b的操作是不准的
8.5.2、四大隔离级别简介
四、JDBC中处理事务
4.1、相关方法(必须掌握)
以下的方法都是Connection中的方法。
setAutoCommit(boolean) 如果true 表示自动提交,false表示开启事务;
commit()提交事务
rollback()回滚事务
4.2、Dao层处理事务
}finally{
//释放资源
JdbcUtils.close(conn, null, null);
}
}
}
4.3、Service层才是处理事务的地方
Service层代码及其注释详解:
可用事务处理方法升级工具类及使用ThreadLocal