1.什么是JDBC:
jdbc是用于连接数据库的连接,简单来说就是用java语言来操作数据库。
2.jdbc的四大类:
-DriverManger:注册驱动
通过Class.forname()去注册驱动
-Connection:连接数据库
Connection con = DriverManger.getConnection(url,user,password)
-Statement:执行sql语句
int executeUpdate(String sql): 执行insert,delete,update操作
ResultSet executeQuery(String sql): 执行select操作,获取查询结果ResultSet
注意,查询的时候需要用到ResultSet去存放查询结果
Statement sta = con.createStatement
ResultSet rs = con.excuteQuery
String sql = "sql语句"
int m = rs.updateQuery(sql);
如果是其他操作则是: int m = sta.excuteUpdate(sql);
-ResulSet:结果集(用于封装查询结果)
封装查询结果
-next(): 行光标指向下一行数据,如果没有数据返回false.
-getXXX(int colIndex):根据列索引获取对应列的数据
-getXXX(String colName):根据列明获取对应列的数据
完整代码如下:
public class EmpDao {
public static void main(String[] args) {
Statement sta = null;
Connection con = null;
ResultSet rs = null;
try {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接对象
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/sys?useUnicode=true&characterEncoding=" +
"utf8&useSSL=false&serverTimezone=UTC","root","123456");
String sql = ("select * from `emp` where `ename` = 'TOM'");
sta = con.createStatement();
rs = sta.executeQuery(sql);
if(rs != null){
System.out.println("查询成功!");
}else{
System.out.println("查询失败!");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
sta.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
3.用jdbc实现增删改查(CURD)
(1).查询的代码
public class UserDao {
public static void main(String[] args) {
UserDao userDao = new UserDao();
userDao.addUser();
}
//查询数据的方法
public void queryUser(){
Statement sta = null;
Connection con = null;
ResultSet rs = null;
//注册驱动
try {
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接对象
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/sys?useUnicode=true&characterEncoding=" +
"utf8&useSSL=false&serverTimezone=UTC","root","123456");
String sql = "select * from `user` where `username` = 'a';";
sta = con.createStatement();
rs = sta.executeQuery(sql);
if(rs != null){
System.out.println("查询成功!");
}else
System.out.println("查询失败!");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
(2).添加数据的代码:
public class UserDao {
public static void main(String[] args) {
UserDao userDao = new UserDao();
userDao.addUser();
}
//添加数据的方法
public void addUser(){
Statement sta = null;
Connection con = null;
ResultSet rs = null;
//注册驱动
try {
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接对象
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/sys?useUnicode=true&characterEncoding=" +
"utf8&useSSL=false&serverTimezone=UTC","root","123456");
String sql = "insert into `user` values ('U_1004','b','666');";
sta = con.createStatement();
int m = sta.executeUpdate(sql);
if(m > 0){
System.out.println("数据插入成功!");
}else
System.out.println("数据插入失败!");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
if(sta != null){
sta.close();
}
if(con != null){
con.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
(3)修改数据的代码
public class UserDao {
public static void main(String[] args) {
UserDao userDao = new UserDao();
userDao.modifyUser();
}
//修改数据的方法
public void modifyUser(){
Statement sta = null;
Connection con = null;
ResultSet rs = null;
//注册驱动
try {
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接对象
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/sys?useUnicode=true&characterEncoding=" +
"utf8&useSSL=false&serverTimezone=UTC","root","123456");
String sql = "update `user` set `username` = '666',`uid` = '666' where `password` = 'zs';";
sta = con.createStatement();
int m = sta.executeUpdate(sql);
if(m > 0){
System.out.println("数据修改成功!");
}else
System.out.println("数据修改失败!");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
if(sta != null){
sta.close();
}
if(con != null){
con.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
(4)删除数据的代码:
public class UserDao {
public static void main(String[] args) {
UserDao userDao = new UserDao();
userDao.deleteUser();;
}
//修改数据的方法
public void deleteUser(){
Statement sta = null;
Connection con = null;
ResultSet rs = null;
//注册驱动
try {
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接对象
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/sys?useUnicode=true&characterEncoding=" +
"utf8&useSSL=false&serverTimezone=UTC","root","123456");
String sql = "delete from `user` where `uid` = '666'";
sta = con.createStatement();
int m = sta.executeUpdate(sql);
if(m > 0){
System.out.println("数据删除成功!");
}else
System.out.println("数据删除失败!");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
if(sta != null){
sta.close();
}
if(con != null){
con.close();
}
if(rs != null){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
总结:在增删改查操作中,大多数都是重复的代码,只有sql语句是不一样的。
4.SQL攻击
(1)什么是SQL攻击:
在需要用户输入的地方,用户输入的是SQL语句的片段,最终用户输入的SQL片段与我们DAO中写的SQL语句合成一个完整的SQL语句!例如用户在登录时输入的用户名和密码都是为SQL语句的片段!
public class UserDao {
public static void main(String[] args) {
UserDao userDao = new UserDao();
User user = userDao.deleteUser("a","123456");
if(user != null){
System.out.println("登录成功!");
}else{
System.out.println("登录失败!");
}
}
public User deleteUser(String username,String password){
Statement sta = null;
Connection con = null;
ResultSet rs = null;
User user = null;
//注册驱动
try {
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接对象
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/sys?useUnicode=true&characterEncoding=" +
"utf8&useSSL=false&serverTimezone=UTC","root","123456");
String sql = "select * from `user` where username = '"+username+"'," +
"password = '"+password+"'";
sta = con.createStatement();
rs = sta.executeQuery(sql);
//遍历结果集
while (rs.next()){
user = new User();
user.setUid(rs.getString("uid"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
}
int m = sta.executeUpdate(sql);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
if(sta != null){
sta.close();
}
if(con != null){
con.close();
}
if(rs != null){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return user;
}
}
先写一个login方法,然后main方法中传入login("a' or '1'='1", "a' or '1'='1");
这个时候也依然会显示登录成功,因为在获取结果集的时候采取的是拼接的方法,所以对应的sql
语句其实是:SELECT * FROM user WHERE username='a' or '1'='1' and password='a' or '1'='1'
所以不管怎样1永远都等于1,不管情况怎么样都会登录成功。
(2)如何解决SQL攻击:
使用PrepaeredStatement进行预编译。
什么是预编译?
通常我们发送一条SQL语句给MySQL服务器时,MySQL服务器每次都需要对这条SQL语句进行校验、解析等操作。但是有很多情况下,我们的一条SQL语句可能需要反复的执行,而SQL语句也只可能传递的参数不一样,类似于这样的SQL语句如果每次都需要进行校验、解析等操作,未免太过于浪费性能了,因此我们提出了SQL语句的预编译。所谓预编译就是将一些灵活的参数值以占位符?的形式给代替掉,我们把参数值给抽取出来,把SQL语句进行模板化。让MySQL服务器执行相同的SQL语句时,不需要在校验、解析SQL语句上面花费重复的时间。
简单来说其实预编译的核心就是把传进去不确定的参数用问好号代替,用来提高效率,并不是字面意思的预编译。
(3)预编译的完整代码
public class UserDao {
public static void main(String[] args) {
UserDao userDao = new UserDao();
User user = userDao.deleteUser("a","123456");
if(user != null){
System.out.println("登录成功!");
}else{
System.out.println("登录失败!");
}
}
public User deleteUser(String username,String password){
PreparedStatement psta = null;
Connection con = null;
ResultSet rs = null;
User user = null;
//注册驱动
try {
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接对象
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/sys?useUnicode=true&characterEncoding=" +
"utf8&useSSL=false&serverTimezone=UTC","root","123456");
String sql = "select * from `user` where username = ? and " +
"password = ?";
psta = con.prepareStatement(sql);
psta.setString(1,username);
psta.setString(2,password);
rs = psta.executeQuery();
//遍历结果集
while (rs.next()){
user = new User();
user.setUid(rs.getString("uid"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
}
int m = psta.executeUpdate(sql);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
if(psta != null){
psta.close();
}
if(con != null){
con.close();
}
if(rs != null){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return user;
}
}
5.DBhelp:jdbc的封装相关,解决增删改查中重复的几个部分
public class DBHelp {
/*数据量四大连接参数*/
private static String driver;
private static String url;
private static String username;
private static String password;
static {
try {
Properties properties = new Properties(); //key-value
properties.load(DBHelp.class.getClassLoader().getResourceAsStream("db.properties"));
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/*获取连接对象*/
public static Connection getConnection(){
try {
return DriverManager.getConnection(url,username,password);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
/*insert,delete,update*/
public static boolean update(Connection connection,String sql,Object...params){
PreparedStatement pstm = null;
try {
//预编译SQL
pstm = connection.prepareStatement(sql);
//注入参数
for(int i = 0 ; i < params.length;i++){
pstm.setObject(i+1,params[i]);
}
//执行SQL
int num = pstm.executeUpdate();
if(num > 0 ){
return true;
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
release(null,pstm,null);
}
return false;
}
/*select*/
public static <T>T query(String sql, ResultSetHanlder<T> hanlder, Object...params){
Connection con = getConnection();
PreparedStatement pstm = null;
ResultSet rs = null;
T value = null;
//预编译SQL
try {
pstm = con.prepareStatement(sql);
//注入参数
for(int i = 0 ; i < params.length;i++){
pstm.setObject(i+1,params[i]);
}
//执行SQL
rs = pstm.executeQuery();
//处理结果集
value = hanlder.resultToData(rs);
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
release(con,pstm,rs);
}
return value;
}
/*释放资源*/
public static void release(Connection con, Statement stm, ResultSet rs){
try {
if(rs != null) {
rs.close();
}
if(stm != null){
stm.close();
}
if(con != null){
con.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
6.事务
(1)什么是事务?
事务就是一组操作,要么都成功,要么都失败,比如说转账业务。
(2)事务的四大属性:
-原子性(Atomicity)
-一致性(Consistency)
-隔离性(Isolation)
-持久性(Durability)
(3)事务的开始、提交、回滚:
(1)开始:start语句
(2)提交:submit
(3)回滚:比如说事务其中有一个失败了则要执行回滚,导致两个事务都执行失败