JDBC复习:Statement-PrepareStatement-事务
JDBC(重点)
用Java操作数据库
JDBC——Java DateBase Connection
SUN公司为了简化开发人员的(对数据库的统一)操作,提供了一个(Java操作数据库的)规范,俗称JDBC
对于开发者来说,只需要掌握JDBC接口的操作即可!
package JDBCtext;
import java.sql.*;
//第一个JDBC程序
public class JdbcFirstDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1,加载驱动
Class.forName("com.mysql.jdbc.Driver");//固定写法,加载驱动
//2,用户信息和URL----相当于MYSQL的数据库连接
//?useUnicode=true&characterEncoding=utf8&useSSL=true
// 支持中文编码 设置字符集utf8 使用安全连接
String url="jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=utf8&useSSL=false";
String username = "root";
String password = "123456";
//3,连接成功,数据库对象,Connection 代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
//4,执行SQL的对象 Statement--->执行sql对象
Statement statement = connection.createStatement();
//5,执行sql对象Statement 去 执行SQL
String sql="SELECT * FROM student";//查询student表
//如果是查询,就执行.executeQuery()
//插入,删除都是更新,用.executeUpdate()
ResultSet resultSet = statement.executeQuery(sql);//返回一个结果集
while(resultSet.next()){
System.out.println("studentno="+resultSet.getObject("studentno"));
System.out.println("studentname="+resultSet.getObject("studentname"));
System.out.println("sex="+resultSet.getObject("sex"));
System.out.println("gradeid="+resultSet.getObject("gradeid"));
System.out.println("phone="+resultSet.getObject("phone"));
System.out.println("address="+resultSet.getObject("address"));
System.out.println("borndate="+resultSet.getObject("borndate"));
System.out.println("email="+resultSet.getObject("email"));
System.out.println("identitycard="+resultSet.getObject("identitycard"));
System.out.println("---------------------------------------");
}
//6,释放SQL
resultSet.close();
statement.close();
connection.close();
}
}
步骤总结:
- 加载驱动
- 连接数据库 DriverManager
- 获得执行sql的对象 Statement
- 获得返回的结果集
- 释放连接
Driver Manager
Class.forName("com.mysql.jdbc.Driver");//固定写法,加载驱动
Connection connection = DriverManager.getConnection(url, username, password);
//connection代表数据库
//数据库设置的这里都可以设置
connection.rollback();//事务回滚
connection.commit();//事务提交
connection.setAutoCommit();//事务自动提交
URL
String url="jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=utf8&useSSL=false";mysql
//=======协议://主机地址:端口号/数据库名?参数1&参数2&参数3=====
//mysql 默认端口号是 3306
//jdbc:mysql://mysql:3306/数据库名?参数1&参数2&参数3
//oralce 默认端口号是 1521
//jdbc:oracle:thin:@localhost:1521:sid
Statement 执行SQL的对象 ----------- .prepareStatement 执行SQL的对象
String sql="SELECT * FROM student";//查询student表
//如果是查询,就执行.executeQuery()
//插入,删除都是更新,用.executeUpdate()
statement.executeQuery();//查询操作,返回一个结果集 ResultSet
statement.execute();//执行任何SQL
statement.executeUpdate();//更新,插入,删除,都是用这个,返回一个受影响的函数
statement.executeBatch();//批量执行SQL
ResultSet 查询的结果集:封装了所有的查询结果
获得指定的数据类型
resultSet.getObject();//不知道列类型的情况下使用
resultSet.getString();
resultSet.getInt();
resultSet.getFloat();
resultSet.getDouble();
resultSet.getBoolean();
遍历–>指针
resultSet.beforeFirst(); //移动到最后面
resultSet.afterLast(); //移动到最前面
resultSet.next(); //移动到下一个数据
resultSet.previous(); //移动到前一行
resultSet.afterLast(row);//移动到指定行
释放资源【必须做】
resultSet.close();
statement.close();
connection.close();//耗费资源,用完就关
1 Statement对象(不安全)
Jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
Statement对象的executeUpdate方法,用于向数据库发送增、删、改的sql语句, executeUpdate执行完后, 将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)。
Statement.executeQuery方法用于向数据库发送查询语句,executeQuery方法返回代表查询结果的ResultSet对象。
数据添加—create
使用executeUpdate(String sql)方法来完成数据添加操作。例如:
Statement statement = connection.createStatement();
String sql = "insert into `grade` (`gradeid`,`gradename`) values(1,'大一'),(2,'大二'),(3,'大三')";
int num = statement.executeUpdate(sql);
if(num>0){
System.out.println("插入成功!");
}
数据删除—delete
使用executeUpdate(String sql)方法来完成数据删除操作。例如:
Statement statement = connection.createStatement();
String sql = "delete from student where id=1";
int num = statement.executeUpdate(sql);
if(num>0){
System.out.println("删除成功!");
}
数据更新—update
使用executeUpdate(String sql)方法来完成数据更新操作。例如:
Statement statement = connection.createStatement();
String sql = "UPDATE `student` SET `sex`='男' WHERE `name`='张三'";
int num = statement.executeUpdate(sql);
if(num>0){
System.out.println("删除成功!");
}
数据查询—select
使用executeQuery(String sql)方法来完成数据查询操作。例如:
Statement statement = connection.createStatement();
String sql = "SELECT * FROM student";
ResultSet resultset = statement.executeQuery(sql);
while(resultSet.next()){
System.out.println("studentno="+resultSet.getObject("studentno"));
//根据获得列的数据类型,分别调用resultset的相应方法映射到Java对象中
}
代码实现—工具类
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String driver = null;
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);
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
//测试:是否正确得到字符串。
System.out.println(driver);
System.out.println(url);
System.out.println(username);
System.out.println(password);
//驱动只需要加载一次
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
//释放连接
public static void release(Connection connection, Statement statement, ResultSet resultSet){
if (resultSet!=null){
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(statement!=null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection!=null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TextJdbc {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();//获取数据库连接
statement = connection.createStatement();//获取SQL执行对象
String sql = "INSERT INTO `school`.`student`(`studentno`, `loginpwd`, `studentname`, `sex`, `gradeid`, `phone`, `address`, `borndate`, `email`, `identitycard`)" +
"VALUES (3000, '123457', '赵六', 0, 2, '1567801234', '四川', '1990-08-01 00:00:00', 'text190@qq.com', '123456198001085231')";
int i = statement.executeUpdate(sql);//受影响的行数
if (i>0){
System.out.println("插入成功!");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
//释放资源
JdbcUtils.release(connection,statement,resultSet);
}
}
}
配置文件 db.properties
driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/school?useUncode=true&characterEncoding=utf8&useSSL=false
username = root
password = 123456
2 SQL注入问题
SQL存在漏洞,会被攻击,导致数据泄露。
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SQLquestion {
public static void main(String[] args) {
// login("小红","13579");
login(" 'or '1=1","' or '1=1");//被攻击,盗用密码
}
//登录业务
public static void login(String username,String password){
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try{
connection = JdbcUtils.getConnection();
statement = connection.createStatement();
String sql = "select * from user where `username` = '"+username+"' and `password` = '"+password+"'";//注意不要写错
System.out.println(sql);
resultSet = statement.executeQuery(sql);
while(resultSet.next()){
System.out.println("==========================");
System.out.println("username = "+resultSet.getString("username"));
System.out.println("password = "+resultSet.getString("password"));
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JdbcUtils.release(connection,statement,resultSet);
}
}
}
3 PrepareStatement对象(安全)
PrepareStatement可以防止SQL注入,并且效率更高
PrepareStatement和Statement一样都是用来进行增删改查的。
package JDBCtext;
import java.sql.*;
public class PrepareStatementText {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement st = null;
try {
connection = JdbcUtils.getConnection();
//区别于Statement
//使用问号?占位符代表参数
String sql ="INSERT INTO `school`.`user`(`username`,`password`) values(?,?)";
st = connection.prepareStatement(sql);//需要一个预编译SQL
//先写SQL,然后不执行
//手动给参数赋值
st.setString(1,"小陈");//给username赋值
st.setString(2,"asdzxc");//给password赋值
//注意点:sql.Date 数据库
// unil.Date 是Java new.Date().getTime()获得时间戳
//到这步为止,SQL已经预编译好了,还没有执行
//执行
int i = st.executeUpdate();//这个里面不需要传入参数
if (i > 0) {
System.out.println("插入成功!");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(connection,st,null);
}
}
}
4 事务
4.1,事务原则:ACID原则
原子性: 要么都成功,要么都失败
【案例】A向B转200块钱
A: 800 - 200 = 600
B:200 + 200 = 400
原子性表示,这两个步骤一起成功,或者一起失败,不能只发生其中一个动作。
一致性: 数据完整性保持一致
【案例】A向B转200块钱
钱的总数,总的价值不会变,总是1000元
持久性
表示事务结束后的数据不随着外界原因导致数据丢失
操作前A:800,B:200
操作后A:600,B:400
如果在操作前(事务还没有提交)服务器宕机或者断电,那么重启数据库以后,数据状态应该为 A:800,B:200
如果在操作后(事务已经提交)服务器宕机或者断电,那么重启数据库以后,数据状态应该为 A:600,B:400
事物没提交,回复原状。
事务提交了,持久化到数据库。
隔离性
针对多个用户同时操作,主要是排除其他事务对本次事务的影响
- 产生的问题
- 脏读——指一个事务读取了另外一个事务未提交的数据。
- 不可重复读——在一个事务内读取表中的某一行数据,多次读取结果不同(这个不一定是错误,只是某些场合不对)
- 幻读(虚读)——是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致(一般是行影响,多了一行)
4.2,执行事务
-- 转账
CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_ general_ ci;
USE shop;
CREATE TABLE `account`(
`id` INT(3) NOT NULL AUTO_ INCREMENT,
`name` VARCHAR(30) NOT NULL,
`money` DECIMAL(9,2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO account(`name`,`money` )
VALUES ('A',2000.00),('B',10000.00);
-- 模拟转账:事务
SET autocommit = 0; -- 关闭自动提交
START TRANSACTION; -- 开启一个事务(一组事务)
I
UPDATE account SET money=money-500 WHERE `name`= 'A';-- A减500
UPDATE account SET money=money+500 WHERE `name`= 'B';-- B加500
CoMMIT; -- 提交事务,就被持久化了!
ROLLBACK; -- 回滚
SET autocommit = 1; -- 恢复默认值
5 用JDBC测试事务
package JDBCtext;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JdbcTransaction {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
//关闭数据库的自动提交,自动回开启事务
connection.setAutoCommit(false);
String sql1 = "update account set money = money-100 where name='小红'";
preparedStatement = connection.prepareStatement(sql1);
preparedStatement.executeUpdate();
String sql2 = "update account set money = money+100 where name='小黄'";
preparedStatement = connection.prepareStatement(sql2);
preparedStatement.executeUpdate();
//业务完毕执行成功
connection.commit();
System.out.println("成功!");
} catch (SQLException throwables) {
try {
connection.rollback();//如果失败就回滚事务
} catch (SQLException e) {
e.printStackTrace();
}
throwables.printStackTrace();
}finally {
JdbcUtils.release(connection,preparedStatement,resultSet);
}
}
}
JdbcUtils这个工具包
package JDBCtext;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String driver = null;
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);
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
/*//测试:是否正确得到字符串。
System.out.println(driver);
System.out.println(url);
System.out.println(username);
System.out.println(password);*/
//驱动只需要加载一次
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
//释放连接
public static void release(Connection connection, Statement statement, ResultSet resultSet){
if (resultSet!=null){
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(statement!=null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection!=null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
dbcpconfig.properties这个配置文件的代码(网上找的)
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/bank
username=root
password=root
#初始化连接
initialSize=10
#最大连接数量
maxActive=50
#最大空闲连接
maxIdle=20
#最小空闲连接
minIdle=5
#超时等待时间以毫秒为单位 6000毫秒/1000等于60秒
maxWait=60000
#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
#注意:“user” 与 “password” 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=gbk
#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true
#driver default指定由连接池所创建的连接的只读(read-only)状态
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=
#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED
本文地址:https://blog.csdn.net/i_see_the_world/article/details/108991624
上一篇: MyBatis缓存实现原理及代码实例解析
下一篇: C# 集合转换为DataTable