04-连接查询
SQL的四种连接方式
内连接
inner join
或者join
外连接
- 左连接
left join
或者left outer join
- 右连接
right join
或者right outer join
- 完全外连接
full join
或者full outer join
-- 创建两个表:
create database testJoin;
-- person 表
-- id、name、cardId
create table person(
id int,
name varchar(20),
cardId int
);
insert into person values(1,'张三',1);
insert into person values(2,'李四',3);
insert into person values(3,'王五',6);
-- card表
-- id、name
create table card(
id int,
name varchar(20)
);
insert into card values(1,'饭卡');
insert into card values(2,'建行卡');
insert into card values(3,'农行卡');
insert into card values(4,'工商卡');
insert into card values(5,'邮政卡');
-- 并没有创建外键
-- 1.inner join 查询(内连接)
-- 内联查询,其实就是两张表中的数据,通过某个相同字段,查询出相关记录数据
mysql> select * from person inner join card on person.cardId=card.id;
-- 2.left join(左外连接)
-- 左外连接,会把左边表里面的所有数据取出来,而右边表中的数据,如果有相等的,就显示出来,如果没有,就会补NULL
mysql> select * from person left join card on person.cardId=card.id;
-- 3.right join(右外连接)
-- 右外连接,会把右边表里面的所有数据取出来,而左边表中的数据,如果有相等的,就显示出来,如果没有,就会补NULL
mysql> select * from person right join card on person.cardId=card.id;
-- 4.full join(全外连接)
mysql> select * from person full join card on person.cardId=card.id;
-- mysql不支持full join,使用左连接union右连接实现
mysql> select * from person left join card on person.cardId=card.id
-> union
-> select * from person right join card on person.cardId=card.id;
MySQL事务
-- mysql事务
-- 在mysql中,事务其实是一个最小的不可分割的工作单元,事务能够保证一个业务的完整性。
-- 比如在银行转账:
a-> -100
update user set money=money-100 where name='a';
b-> +100
update user set money=money+100 where name='b';
-- 实际程序中,如果只有一条语句执行成功,而另一条没有执行成功,就会出现数据前后不一致
-- 多条sql语句,可能会有要么同时成功,要么就同时失败的要求
-- 事务的四大特征(ACID)
A 原子性:事务是最小的单位,不可再分割
C 一致性:事务执行之前和执行之后都必须处于一致性状态,要么同时成功要么同时失败
I 隔离性:事务1 和 事务2 之间是具有隔离性的
D 持久性:事务一旦结束(commit,rollback),就不可以返回
持久性
-- 持久性是指一个事务一旦被提交,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
-- mysql默认是开启事务的(默认自动提交)。
mysql> select @@autocommit;
-- 默认事务开启的作用:当我们去执行一个sql语句的时候,效果会立即体现出来,且不能回滚
-- 事务回滚(rollback):撤销sql语句执行效果
mysql> create database bank;
mysql> create table user(
-> id int primary key,
-> name varchar(20),
-> money int
-> );
mysql> insert into user values(1,'a',1000)
mysql> rollback; -- 默认无法回滚,数据会自动提交
-- 关闭mysql的自动提交(commit)
mysql> set autocommit=0;
mysql> select @@autocommit;
mysql> insert into user values(2,'b',1000);
mysql> select * from user;
mysql> rollback; -- 回滚
mysql> select * from user;
mysql> insert into user values(2,'b',1000); -- 再次添加数据
mysql> commit; -- 手动提交数据(持久性)
mysql> rollback; -- 不可回滚(持久性)
mysql> select * from user;
自动提交 @@autocommit=1;
手动提交 commit;
事务回滚 rollback;
事务给我们提供了一个返回的机会。
使用 begin;
或 start transaction;
都可以帮我们手动开启一个事务
mysql> set autocommit=1; -- 打开自动提交
mysql> select @@autocommit;
手动开启事务(1) begin;
mysql> begin;
mysql> update user set money=money-100 where name='a';
mysql> update user set money=money+100 where name='b';
mysql> select * from user;
mysql> rollback;
mysql> select * from user;
手动开启事务(2) start transaction;
mysql> start transaction;
mysql> update user set money=money-100 where name='a';
mysql> update user set money=money+100 where name='b';
mysql> select * from user;
mysql> rollback;
mysql> select * from user;
事务开启之后,一旦commit
提交,就不能回滚,事务在提交的时候就结束了。
隔离性
-- 隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离
-- 数据库为事务提供了多种隔离级别:
1.read uncommitted; 读未提交的(脏读)
2.read committed; 读已经提交的(不可重复读)
3.repeatable read; 可以重复读(幻读)
4.serializable; 串行化
数据库的隔离级别:
-- 查看mysql默认隔离级别
mysql> select @@global.transaction_isolation; -- 系统级别
mysql> select @@transaction_isolation; -- 会话级别
-- 修改mysql隔离级别
mysql> set [ global.transaction_isolation | transaction_isolation ]='隔离级别';
mysql> set [glogal | session] transaction isolation level [隔离级别]
1、脏读
如果有事务a和事务b
a事务对数据进行操作,在操作的过程中,事务没有被提交,但是b可以看见a操作的结果
-- 情形模拟
mysql> insert into user values(3,'小明',1000);
mysql> insert into user values(4,'淘宝店',1000);
mysql> select * from user;
-- 打开两个命令行窗口
-- 修改隔离级别
mysql> set session transaction isolation level read uncommitted;
mysql> select @@transaction_isolation;
-- 转账:小明在淘宝店买鞋子:800块钱
-- 小明->成都ATM
-- 淘宝店->广州ATM
mysql> start transaction;
mysql> update user set money=money-800 where name='小明';
mysql> update user set money=money+800 where name='淘宝店';
mysql> select * from user;
-- 给淘宝店打电话,说你去查一下,是不是到账了
-- 淘宝店在广州查账
mysql> select * from user;
-- 发货,晚上消费1800
-- 小明->成都
mysql> rollback;
mysql> select * from user;
-- 淘宝店->结账发现钱不够
mysql> select * from user;
-- 脏读:一个事务读到了另外一个事务没有提交的数据
-- 如果两个不同的对方都在进行操作,如果事务a开启之后,他的数据可以被其他事务读取到,这样就会出现脏读,只要该事务不提交,则所有操作都将回滚
-- 实际开发中是不允许脏读出现的
2、不可重复读
-- 不可重复读(read committed)是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交
-- 打开两个命令行窗口
-- 修改隔离级别为 READ-COMMITTED
mysql> set session transaction isolation level read committed; -- 会话级别
mysql> select @@transaction_isolation;
-- 小张开启事务:
mysql> start transaction;
mysql> select * from user;
-- 出门上厕所
-- 小王开启事务:
mysql> start transaction;
mysql> insert into user values(5,'c',100);
mysql> commit;
mysql> select * from user;
-- 小张上完厕所回来
mysql> select avg(money) from user;
-- money的平均不是1000,变少了?
-- 不可重复读和脏读的区别,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据
-- 小张再次核对数据
mysql> select * from user;
3、幻读
-- 打开两个命令行界面
-- 修改隔离级别为 repeatable read
mysql> set global transaction isolation level repeatable read; -- 系统级别
mysql> select @@global.transaction_isolation;
mysql> select @@transaction_isolation;
-- 小明开启事务:
mysql> start transaction;
mysql> select * from user;
-- 小红开启事务:
mysql> start transaction;
mysql> insert into user values(6,'d',1000);
mysql> commit;
mysql> select * from user;
-- 小明添加数据
mysql> insert into user values(6,'d',1000);
1062 - Duplicate entry '6' for key 'user.PRIMARY' -- 失败
-- 查看列表
mysql> select * from user;
这种现象就叫幻读
事务a和事务b同时操作同一张表,事务a提交数据,无法被事务b读到,也就造成了幻读。
-- 小明结束事务
mysql> commit;
-- 再次查看列表
mysql> select * from user;
4、串行化
-- 打开两个命令行窗口
-- 修改隔离级别为串行化
mysql> set session transaction isolation level serializable;
mysql> select @@transaction_isolation;
mysql> select * from user;
-- 小明开启事务
mysql> start transaction;
-- 小红开启事务
mysql> start transaction;
-- 小明插入数据
mysql> insert into user values(7,'张三',1000);
mysql> commit;
mysql> select * from user;
-- 小红查看列表
mysql> select * from user;
-- 小明再次开启事务
mysql> start transaction;
mysql> insert into user values(8,'李四',1000);
1205 - Lock wait timeout exceeded; try restarting transaction
-- sql语句被卡住了?
-- 当user表被另外一个事务操作的时候,其他事务里面的写操作,是不可以进行的
-- 进入排队状态(串行化),直到小红那边的事务结束之后,小明的这个写操作才会执行。
-- 小红结束事务
mysql> commit;
-- 小明继续插入数据
mysql> insert into user values(8,'李四',1000);
mysql> commit;
mysql> select * from user;
-- 总结:
-- 串行化的问题是,性能特差!!
-- 性能排行:
READ-UNCOMMITTED > READ-COMMITTED > REPEATABLE-READ > SERIALIZABLE
-- 隔离级别越高,性能越差
-- mysql 默认隔离级别为 REPEATABLE-READ
JDBC
SUN公司为了简化开发人员的操作,提供了一个Java操作数据库的规范,简称JDBC (Java Database Connectivity), 是一种用于执行SQL语句的Java API,即Java数据库编程接口。
下载数据库驱动包mysql-connector-java-8.0.21.jar,与电脑上的数据库版本相对应。
第一个JDBC程序
1、创建测试数据库
mysql> create database jdbcStudy character set utf8 collate utf8_general_ci;
mysql> use jdbcStudy;
mysql> create table users(
-> id int primary key,
-> name varchar(40),
-> password varchar(40),
-> email varchar(60),
-> birthday DATE
-> );
mysql> insert into users values(1,'zhansan','123456','zhangsan@sina.com','1980-12-04'),(2,'lisi','123456','lisi@sina.com','1981-12-04'),(3,'wangwu','123456','wangwu@sina.com','1979-12-04');
mysql> select * from users;
2、在IDEA创建一个普通项目,导入数据库驱动
导入完成。
3、编写测试代码
package com.wang.lesson01;
import java.sql.*;
//我的第一个JDBC程序
public class JdbcFirstDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.加载驱动
Class.forName("com.mysql.cj.jdbc.Driver"); //固定写法
//2.用户信息和url
//userUnicode=true -- 支持中文编码
// &characterEncoding=utf8 -- 设置中文字符集utf8
// &useSSL=true -- 使用安全连接
//执行后时区问题报错 差了8个小时 解决办法,在url后面加上 serverTimezone=GMT%2B8(即GMT+8) 或是 serverTimezone=Hongkong
String url = "jdbc:mysql://localhost:3306/jdbcStudy?userUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Hongkong";
String username = "root";
String password = "201314";
//3.连接成功,数据库对象 Connection 代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
//4.执行SQL的对象
Statement statement = connection.createStatement();
//5.执行SQL的对象去执行SQL,可能存在结果,查看返回结果
String sql = "select * from users";
ResultSet resultSet = statement.executeQuery(sql); //返回的结果集
//resultSet结果集中封装了我们全部的查询出来的结果
while (resultSet.next()) {
System.out.println("id=" + resultSet.getObject("id"));
System.out.println("name=" + resultSet.getObject("name"));
System.out.println("password=" + resultSet.getObject("password"));
System.out.println("email=" + resultSet.getObject("email"));
System.out.println("birthday=" + resultSet.getObject("birthday"));
System.out.println("======================================================");
}
//6.释放连接
resultSet.close();
statement.close();
connection.close();
}
}
总结:
DriverManager
// DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.cj.jdbc.Driver"); //固定写法,加载驱动
Connection connection = DriverManager.getConnection(url, username, password);
// connection 代表数据库
connection.commit(); // 事务提交
connection.rollback(); // 事务回滚
connection.setAutoCommit(false); // 数据库设置自动提交
URL
String url = "jdbc:mysql://localhost:3306/jdbcStudy?userUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Hongkong";
//协议://主机地址:端口号/
//mysql 默认端口号 3306
//jdbc:mysql://localhost:3306/数据库名?参数1&参数2&参数3&
//oracle 默认端口号 1521
//jdbc:oracle:thin:@localhost:1521:sid
Statement执行SQL的对象 PrepareStatement
String sql = "select * from users"; //编写SQL
statement.executeQuery(); //查询操作返回ResultSet
statement.execute(); //执行任何SQL
statement.executeUpdate(); //更新、插入、删除。都是用这个,返回一个受影响的行数
ResultSet查询的结果集:封装了所有的查询结果
获得指定的数据类型
resultSet.getString(); //在不知道列类型的时候使用
//知道列的类型就使用指定的类型
resultSet.getInt();
resultSet.getFloat();
resultSet.getDate();
resultSet.getObject();
...
resultSet.beforeFirst(); //移动到最前面
resultSet.afterLast(); //移动到最后面
resultSet.next(); //移动到下一个数据
resultSet.previous(); //移动到前一行
resultSet.absolute(row); //移动到指定行
释放资源
resultSet.close();
statement.close();
connection.close(); //耗资源,用完关掉!
statement对象
JDBC中的statement对象用于向数据库发生SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
Statement对象的executeUpdate方法,用于向数据库发送增、删、改的sql语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发生了改变)。
Statement.executeQuery方法用于向数据库发送查询语句,executeQuery方法返回代表查询结果的ResultSet对象。
CRUD操作-create
使用execute Update(String sql)方法完成数据添加操作,示例操作:
Statement st = connection.createStatement();
String sql = "insert into user(...) values(...)";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("插入成功!!!");
}
CRUD操作-delete
使用executeUpdate(String sql)方法完成数据删除操作,示例操作:
Statement st = connection.createStatement();
String sql = "delete from user where id=1";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("删除成功!!!");
}
CRUD操作-update
使用executeUpdate(String sql)方法完成数据修改操作,示例操作:
Statement st = connection.createStatement();
String sql = "update user set name = '' where name='' ";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("修改成功!!!");
}
CRUD操作-read
使用executeQuery(String sql)方法完成数据查询操作,示例操作:
Statement st = connection.createStatement();
String sql = "select * from user where id=1";
int num = st.executeQuery(sql);
if(num>0){
//根据获取的数据类型,分别调用rs的相应方法映射到java对象中
}
封装连接代码
在src目录下新建file->db.properties,添加如下代码:
driver=com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/jdbcStudy?userUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8
username = root
password = 201314
新建工具类utils,写入封装代码:
package com.wang.lesson02.utils;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String url = null;
private static String username = null;
private static String password = null;
static {
try {
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
String dirver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
//驱动只用加载一次
Class.forName(dirver);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
//释放资源
public static void release(Connection conn, Statement st, ResultSet rs){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(st!=null){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
完成。
向mysql插入数据
package com.wang.lesson02;
import com.wang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestInsert {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection(); //获取数据库连接
st = conn.createStatement(); //获得SQL的执行对象
String sql ="insert into users(id,name,password,email,birthday)"
+"values(4,'Michael','123456','214315@qq.com','2021-2-1');";
int i = st.executeUpdate(sql); //i代表受影响的行数
if(i>0){
System.out.println("插入成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
报了异常,但是插入成功!
删除数据
同样的,
package com.wang.lesson02;
import com.wang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestDelete {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection(); //获取数据库连接
st = conn.createStatement(); //获得SQL的执行对象
String sql ="delete from users where id=4";
int i = st.executeUpdate(sql); //i代表受影响的行数
if(i>0){
System.out.println("删除成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
更新数据
package com.wang.lesson02;
import com.wang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestUpdate {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection(); //获取数据库连接
st = conn.createStatement(); //获得SQL的执行对象
String sql ="update users set name = '张三' where id=1";
int i = st.executeUpdate(sql); //i代表受影响的行数
if(i>0){
System.out.println("更新成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
测试查询
package com.wang.lesson02;
import com.wang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestSelect {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
//SQL
String sql = "select * from users where id=1";
rs = st.executeQuery(sql);//查询完毕会返回一个结果集
while (rs.next()){
System.out.println(rs.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
SQL注入问题
sql存在漏洞,会被攻击导致数据泄露。SQL会被拼接
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
package com.wang.lesson02;
import com.wang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SQLInjection {
public static void main(String[] args) {
//login("张三","123456"); //正常登录
login(" 'or '1=1"," 'or '1=1"); //sql注入
}
//登录业务
public static void login(String username,String password){
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
//SQL
String sql = "select * from users where name='"+username+"' and password='"+password+"'";
rs = st.executeQuery(sql);//查询完毕会返回一个结果集
while (rs.next()){
System.out.println(rs.getString("name"));
System.out.println(rs.getString("password"));
System.out.println("==================================");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
PreParedStaterment对象
PreParedStaterment可以防止SQL注入,并且效率更高。
新增
package com.wang.lesson03;
import com.wang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.util.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestInsert {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
try {
conn = JdbcUtils.getConnection();
//区别
//使用 ? 占位符代替参数
String sql = "insert into users(id,name,password,email,birthday) value(?,?,?,?,?)";
st = conn.prepareStatement(sql);//预编译SQl,先写sql,然后不执行
//手动给参数赋值
st.setInt(1,4); // id 1代表第一个?
st.setString(2,"赵匡胤");
st.setString(3,"123456");
st.setString(4,"3426527@qq.com");
// sql.Date 数据库的Date
// util.Date Java的Date new Date().getTime()获得时间戳
st.setString(5, String.valueOf(new java.sql.Date(new Date().getTime())));
//执行
int i = st.executeUpdate();
if(i>0){
System.out.println("插入成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,null);
}
}
}
删除
import com.wang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestDelete {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
try {
conn = JdbcUtils.getConnection();
//区别
//使用 ? 占位符代替参数
String sql = "delete from users where id=?";
st = conn.prepareStatement(sql);//预编译SQl,先写sql,然后不执行
//手动给参数赋值
st.setInt(1,4);
//执行
int i = st.executeUpdate();
if(i>0){
System.out.println("删除成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,null);
}
}
}
更新
package com.wang.lesson03;
import com.wang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestUpdate {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
try {
conn = JdbcUtils.getConnection();
//区别
//使用 ? 占位符代替参数
String sql = "update users set name=? where id=?";
st = conn.prepareStatement(sql);//预编译SQl,先写sql,然后不执行
//手动给参数赋值
st.setString(1,"李四");
st.setInt(2,2);
//执行
int i = st.executeUpdate();
if(i>0){
System.out.println("更新成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,null);
}
}
}
查询
package com.wang.lesson03;
import com.wang.lesson02.utils.JdbcUtils;
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) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql = "select * from users where id=?"; //编写sql
st = conn.prepareStatement(sql);// 预编译,不执行
st.setInt(1,1);//传递参数
rs = st.executeQuery();//执行
if(rs.next()){
System.out.println(rs.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
SQL注入
package com.wang.lesson03;
import com.wang.lesson02.utils.JdbcUtils;
import java.sql.*;
public class SQLInjection {
public static void main(String[] args) {
login("张三","123456"); //正常登录
//login(" 'or '1=1"," 'or '1=1"); //sql注入 没有结果也没报错
}
//登录业务
public static void login(String username,String password){
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
//PreparedStatement 防止SQL注入
String sql = "select * from users where name=? and password=?";
st = conn.prepareStatement(sql);
st.setString(1,username);
st.setString(2,password);
rs = st.executeQuery(); //查询完毕会返回一个结果集
while (rs.next()){
System.out.println(rs.getString("name"));
System.out.println(rs.getString("password"));
System.out.println("==================================");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
PreParedStaterment防止SQL注入的本质:把传递进来的参数当作字符,假设其中存在转义字符,就直接忽略。
使用IDEA连接数据库
![img](https://raw.githubusercontent.com/wys49413/Warehouse/master/LWQW6`]E3I](5%7BX2K%602U~5A.png)
更新数据
事务
将user表copy到jdbcstudy数据库中。
import com.wang.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestTransaction1 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
//关闭自动提交,自动开启事务
conn.setAutoCommit(false);
String sql1 = "update user set money = money-100 where name ='a'";
st = conn.prepareStatement(sql1);
st.executeUpdate();
String sql2 = "update user set money = money+100 where name ='b'";
st = conn.prepareStatement(sql2);
st.executeUpdate();
//业务完毕,提交事务
conn.commit();
System.out.println("成功");
} catch (SQLException e) {
try {
conn.rollback();//如果失败则回滚事务
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
执行成功!
代码实现
1.开启事务conn.setAutoCommit(false);
2.一组业务执行完毕,提交事务 conn.commit();
3.可以在catch语句中显示定义的回滚语句,默认失败就会回滚conn.rollback();