标签:JDBC、行级锁、乐观锁与悲观锁
MySQL :: Download Connector/Jhttps://dev.mysql.com/downloads/connector/j/
2.1 如果是记事本开发,则需要把上面下载的驱动包引入环境变量,在classpath引入下载驱动包的路径,这样编译执行时才能让java找到。
2.2 如果是IDEA开发,只需要在项目文件夹下新建名为lib的包,然后右键add as library即可。
3.1 注册驱动→告诉java程序我要开始连接Mysql数据库了
DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());//高版本用这个
DriverManager.registerDriver(new com.mysql.jdbc.Driver());//低版本用这个
Class.forName("com.mysql.cj.jdbc.Driver");//Mysql高版本用这个
Class.forName("com.mysql.jdbc.Driver");//Mysql低版本用这个
【注意】由于该方法参数是字符串,故可结合.properties配置文件实现实时读取功能,实现让客户傻瓜式操作。
package src.JDBC;
import java.sql.*;
import java.util.ResourceBundle;
public class gaijin {
public static void main(String[] args) {
// DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
//资源绑定器绑定配置文件;
ResourceBundle bunch = ResourceBundle.getBundle("src/JDBC/jdbc");
String driver = bunch.getString("driver");
String url = bunch.getString("url");
String username = bunch.getString("username");
String password = bunch.getString("password");
Statement sta = null;
Connection col = null;
//注册驱动、获取连接、获取数据库对象、查询、获得结果、终结资源
try {
// String driver = "com.mysql.cj.jdbc.Driver";
Class.forName(driver);
// String url = "jdbc:mysql://localhost:3306/mydb";
// String username = "root";
// String password = "123456";
col = DriverManager.getConnection(url,username,password);
//数据库的对象为com.mysql.cj.jdbc.ConnectionImpl@f0f277
System.out.println("数据库的对象为"+col);
//获取对象
sta = col.createStatement();
//执行sql语句
// String sql = "insert into hh values('张三',300,3000.22);";
String sql = "update hh set id = 800 where name = '张三'";
//count为历史记录条数;专门执行DML语句的insert delete update
int count = sta.executeUpdate(sql);
//处理结果集合
} catch (SQLException e) {
e.printStackTrace();
}
catch(ClassNotFoundException ex){
ex.printStackTrace();
}
finally{
//释放资源
//遵循从小到大关闭所有对象,分别对齐try-catch→保证都能关闭;
try{
if(sta!=null){
sta.close();
}
}
catch(SQLException ex){
ex.printStackTrace();
}
try{
if(col!=null){
col.close();
}
}
catch(SQLException ex){
ex.printStackTrace();
}
}
}
}
3.2 建立连接→java程序正式与数据库进程通信,建立管道
Connection col = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","123456");
3.3 返回对象→java一切都是对象,我们需要先获取连接对象,传入sql语句
Statement sta = col.createStatement();
PreparedStatement ps = col.PrepareStatement();
3.4 执行sql语句→执行sql语句即可→一般是DQL和DML语言居多
sta.executeUpdate(sql);
ps.executeUpdate();
3.5 遍历结果集→如果采用select语句,则对于获取的结果可以遍历的方式打印出来
while(rs.next()){//rs.next 为该行的下一个值;
// String name = rs.getString(1);
//把所有值返回成String类型的值;
//上述可以将参数改为字段名名,即RS对象的列名,如果改变了则必须跟着改变;
String name = rs.getString("name");//把所有值返回成String类型的值;
//JDBC中列从1开始,而不是0;
// String id = rs.getString(2);
//还可以以int和Double类型读取;
int id = rs.getInt("id");
String salary = rs.getString(3);
System.out.println("name is "+name +
" id is "+ id + " salary is "
+ salary);}
3.6 关闭资源→关闭占用的连接、对象、返回的结果
//遵循从小到大关闭所有对象,分别对齐try-catch→保证都能关闭;
finally{
if(rs !=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(sta !=null) {
try {
sta.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(col !=null) {
try {
col.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
package src.JDBC;
import java.sql.*;
/**
* @author zhangsan
* @create 2021-11-23 13:36
*/
public class outcomedealWith {
public static void main(String[] args) {
Connection col = null;
Statement sta = null;
ResultSet rs = null;
try{
Class.forName("com.mysql.cj.jdbc.Driver");
col = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","123456");
sta = col.createStatement();
String sql = "select * from hh;";
rs = sta.executeQuery(sql);
//处理结果集;
while(rs.next()){//rs.next 为该行的下一个值;
// String name = rs.getString(1);//把所有值返回成String类型的值;
//上述可以将参数改为字段名名,这个名字为RS对象的列名,
//如果改变了则必须跟着改变;
String name = rs.getString("name");
//把所有值返回成String类型的值;
//JDBC中列从1开始,而不是0;
// String id = rs.getString(2);
//还可以以int和Double类型读取;
int id = rs.getInt("id");
String salary = rs.getString(3);
System.out.println("name is "+name + " id is "+ id +
" salary is "+ salary);
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(rs !=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(sta !=null) {
try {
sta.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(col !=null) {
try {
col.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
package src.JDBC;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/**
* @author zhangsan
* @create 2021-11-23 20:22
*/
public class loginTest_laodu {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
//初始化用户输入界面
Map userInfo = initUi();//返回用户输入的密码和用户信息→hashmap;
//收集用户提交的的信息
boolean isSuccess = login(userInfo);
System.out.println(isSuccess?"登录成功":"登陆失败");
long endTime = System.currentTimeMillis();
System.out.println("耗时"+(endTime - startTime)+"ms");
//连接数据库
//验证并返回
}
/*
* 用户登录
* @param userInfo 用户登录信息
* @return false表示失败,true表示登录成功
* */
private static boolean login(Map userInfo) {
//与JDBC尝试连接
boolean loginSuccess = false;
String username = userInfo.get("loginName");
String password = userInfo.get("loginPwd");
Connection col = null;
Statement sta = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
col = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","123456");
sta = col.createStatement();
String sql = "select * from user where username ="+("'"+username+"'")+"and userpassword ="+("'"+password+"';");
System.out.println(sql);
rs = sta.executeQuery(sql);
while(rs.next()){
loginSuccess = true;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch(SQLException e ){
return false;
}finally {
if (rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(sta!=null){
try {
sta.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (col !=null) {
try {
col.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return loginSuccess;
}
//
private static Map initUi() {
Map userinfoBag = new HashMap<>();
Scanner in = new Scanner(System.in);
System.out.println("请输入你的用户名:");
String loginName = in.nextLine();
System.out.println("请输入你的密码:");
String loginPwd = in.nextLine();
userinfoBag.put("loginName",loginName);
userinfoBag.put("loginPwd",loginPwd);
return userinfoBag;
}
}
此时,有如下意料之外的结果: 其实,SQL注入本质是把用户输入的信息与SQL语句一起编译,将用户的输入信息直接作为SQL语句进行查询,此时可以调用PreparedStatement方法,进行预编译,然后传“值”,这样就可以避免SQL注入问题,即如下的模板2.
package src.JDBC;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/**
* @author zhangsan
* @create 2021-11-23 20:31
*/
public class loginTest_laodu_changeVersion {
public static void main(String[] args) {
//初始化用户输入界面
Map userInfo = initUi();//返回用户输入的密码和用户信息→hashmap;
//收集用户提交的的信息
boolean isSuccess = login(userInfo);
System.out.println(isSuccess?"登录成功":"登陆失败");
//连接数据库
//验证并返回
}
/*
* 用户登录
* @param userInfo 用户登录信息
* @return false表示失败,true表示登录成功
* */
private static boolean login(Map userInfo) {
//与JDBC尝试连接
boolean loginSuccess = false;
String username = userInfo.get("loginName");
String password = userInfo.get("loginPwd");
Connection col = null;
PreparedStatement ps = null; //变为预编译的Statemnet对象
ResultSet rs = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
col = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","123456");
//第三步:获取预编译数据库对象;
// String sql = "select * from user where username ="+("'"+username+"'")+"and userpassword ="+("'"+password+"';");
String sql = "select * from user where username =? and userpassword =?";
//?用作占位符,传入“值”,不能加引号;上面是sql语句的框架;
//程序执行到此处,把sql语句框子发送给DBMS,然后后者进行sql语句的预先编译;
ps = col.prepareStatement(sql);//对应的也要变化调用对象的方法;这里就是动词了,而上面类名是名词
//给占位符传值:第一个问哈下标为1,第二个问哈下标为2;
ps.setString(1,username);//setString自动填入?并是字符串,即自动加上'';
ps.setString(2,password);
rs = ps.executeQuery();//这里括号内不要写sql了!!
while(rs.next()){
loginSuccess = true;
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch(SQLException e ){
return false;
}finally {
if (rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(ps!=null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (col !=null) {
try {
col.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return loginSuccess;
}
//
private static Map initUi() {
Map userinfoBag = new HashMap<>();
Scanner in = new Scanner(System.in);
System.out.println("请输入你的用户名:");
String loginName = in.nextLine();
System.out.println("请输入你的密码:");
String loginPwd = in.nextLine();
userinfoBag.put("loginName",loginName);
userinfoBag.put("loginPwd",loginPwd);
return userinfoBag;
}}
前者有sql注入问题,后者没有
后者效率更高;
原理简介:mysql中,如果出现同样的语句(包括空格等),则不会编译,直接返回;
Mysql也是高级语言,会编译然后执行
编译一次,执行N次,每次都是传“值”;
后者会在编译阶段进行类型安全检查,更安全;
故99%用PreparedStatement,以下情况必须使用前者。
业务要求必须使用SQL语句拼接的时候;
例如京东商城购物界面需要按照价格降序,此时相当于加上order by xx desc,因此就不能用占位符(因为占位符是值,而不是自有的字段),故此时必须拼接
select * from tableName where name ='444' for update;
//即在语句后加上for update,加上锁。
package src.JDBC;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* drop table if exists shiwu;
* create table shiwu(
* actno int,
* balance double(7,2)
* );
* insert into shiwu values(1,2000);
* insert into shiwu values(2,4000);
* commit;
* select * from shiwu;
*/
public class Transaction_Bank {
public static void main(String[] args) {
Connection col = null;
PreparedStatement ps = null;
// ResultSet rs = null;
try {
//1.驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.连接
col = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","123456");
//将自动提交机制修改为false;
col.setAutoCommit(false);//设置事务为手动提交!!!
//3.获取对象→预编译
String sql = "update shiwu set balance =? where actno = ?";
ps = col.prepareStatement(sql);
ps.setDouble(1,3000);
ps.setInt(2,1);
int count = ps.executeUpdate();
String s =null;
s.toString();
String sq2 = "update shiwu set balance =? where actno = ?";
ps = col.prepareStatement(sq2);
ps.setDouble(1,3000);
ps.setInt(2,2);
count += ps.executeUpdate();
System.out.println(count==2?"转账成功":"转账失败");
//手动提交,能到这里说明没有异常;
col.commit();
//5.遍历结果集→省略
} catch(Exception e){
if(col!=null){
try {
col.rollback();//出现异常则事务回滚,全部清空;
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}finally {
//6.关闭:
if(ps!=null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(col!=null){
try {
col.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
package src.JDBC;
import java.sql.*;
import java.util.ResourceBundle;
/**
* @author zhangsan
* @create 2021-11-23 22:21
*/
public class Utils {
static{//静态代码块只执行一次,类加载的时候执行,这里可以把注册驱动执行一次即可;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private Utils() {
//防止new对象;
}
public static Connection getConnection(String username,String password) throws SQLException{
Connection col =null;
col = DriverManager.getConnection("jdbc:mysql://localhost:3306",username,password);
return col;
}
public static Connection getConnection() throws SQLException{
Connection col = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","123456");
return col;
}
/**
* 关闭资源
* @param col 连接对象
* @param ps PreparedStatement对象或者Statement对象
* @param rs 结果集对象
*/
public static void close(Connection col, 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(col!=null){//在原来的版本中,不需要catch异常,故不用抛出,自己处理即可;
try {
col.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}