JDBC ¶
简介 ¶
- JDBC: Java Database Connectivity(Java语言连接数据库)
- JDBC是sun公司定制的一套接口(Java.sql.*) 接口都有调用者和实现者 面向接口调用、面向接口写实现类都是面向接口编程 面向接口:解耦合,降低偶尔度,提高程序扩展力;多态是典型的面向接口编程
- 数据库厂家实现接口(驱动),Java程序员调用接口
- 首先官网下载对应的Java驱动包,然后将其配置到环境变量classpath中,使用IDEA不需要配置以上环境变量
- JDBC变成六步
- 注册驱动:告诉Java程序,即将链接哪个品牌数据库
- 获取链接:表示JVM进程与数据库进程之间的通道打开了,这属于进程间通信,重量级的,使用完后需要释放
- 获取数据库操作对象:专门执行sql语句的对象
- 执行sql语句:DQL,DML
- 执行查询结果集:只有当第四步执行的是select语句时,才有这一步
- 释放资源:释放资源,Java与mysql之间属于进程间通信
编程六步 ¶
- 结果集有next()方法(有点像是迭代器),有数据返回true,没有数据返回false; getString()方法,不管数据库字段类型是什么,取出都是String类型; 还可以使用int取出,getInt(); 可以使用下标取出,也可以使用字段名取出(查询的字段名) JDBC中下标从1开始
java
1import Java.sql.*;
2import Java.util.*;
3public class JdbcTest01
4{
5 public static void main (String[] args) throws Exception
6 {
7 //使用资源绑定器
8 ResourceBundle bundle=ResourceBundle.getBundle("jdbc");
9
10 Connection conn=null;
11 Statement stmt=null;
12 ResultSet rs=null;
13 try{
14 //1.注册驱动
15 //DriverManager.registerDriver(new com.mysql.jdbc.Driver());
16 //注册驱动另一种方式,在静态代码块中,使用反射机制加载类,参数是字符串,
17 //可以写到properties文件中
18 Class.forName(bundle.getString("driver"));
19
20 //2.获取连接
21 /*
22 url包括协议、IP、port、资源名
23 */
24 String url=bundle.getString("url");
25 String user=bundle.getString("user");
26 String password=bundle.getString("password");
27 conn=DriverManager.getConnection(url,user,password);
28 System.out.println(conn);
29
30 //3.获取数据库操作对象(专门执行sql语句的)
31 stmt=conn.createStatement();
32
33 //4.执行sql语句
34 String sql="insert into t_user(name) values ('北京')";
35 //专门执行DML语句(insert delete update);返回值int为影响记录条数
36 int count=stmt.executeUpdate(sql);
37 System.out.println(count==1?"插入成功":"插入失败");
38 sql="select * from emp;";
39 //专门执行DQL语句,ResultSet executeQuery(select)
40 rs=stmt.executeQuery(sql);
41
42 //5.查询结果集
43 while(rs.next()){//看是否还有数据
44 System.out.print(rs.getString("ename")+"."); //查询出结果的字段名
45 System.out.print(rs.getString("sal")+".");
46 System.out.print(rs.getString("deptno")+".");
47 System.out.print(rs.getString("job")+".");
48 System.out.println();
49
50 }
51 }catch(Exception e){
52 e.printStackTrace();
53 }finally{
54 //6.释放资源,遵循从小到大依次关闭
55 try{
56 if(rs!=null){
57 rs.close();
58 }
59 }catch(SQLException e){
60 e.printStackTrace();
61 }
62 try{
63 if(stmt!=null){
64 stmt.close();
65 }
66 }catch(SQLException e){
67 e.printStackTrace();
68 }
69 try{
70 if(conn!=null){
71 conn.close();
72 }
73 }catch(SQLException e){
74 e.printStackTrace();
75 }
76 }
77
78 }
79}资源绑定器 ¶
jdbc.properties
properties
1driver=com.mysql.jdbc.Driver
2url=jdbc:mysql://localhost:3306/mydata?useSSL=false
3user=root
4password=123456java
1//使用资源绑定器
2ResourceBundle bundle=ResourceBundle.getBundle("jdbc");
3String url=bundle.getString("url");
4String user=bundle.getString("user");
5String password=bundle.getString("password");sql注入 ¶
原因:用户输入的信息中含有sql语句关键字,并且这些关键字参与sql语句的编译过程,导致sql语句的原意被扭曲
解决
- 用户输入信息不参与sql语句编译过程,预编译,占位符?
- sql语句如果完全不变,那么第二次执行时不会重新编译;所以有PreparedStatement预编译,且它执行效率高于Statement;PreparedStatement会在编译阶段做类型的安全检查
- Statement(数据库操作接口)更换为PreparedStatement(预编译数据库操作接口,继承Statement);PreparedStatement预先对sql语句进行编译
- ps=conn.prepareStatement(sql);获取预编译操作对象;这里会发送sql语句框架发送到DBMS,然后DBMS进行预编译;?占位符
- 给?占位符传值,第一个是问号下标是1,第二个问号下标是2,JDBC中所有下标从1开始;ps.setString(1,username);ps.setString(2,password);这里会根据传值类型自动书写sql语句
- res=ps.executeQuery();//执行sql
java1Connection conn=null; 2PreparedStatement ps=null;//预编译数据库操作对象 3ResultSet res=null; 4try { 5 Class.forName("com.mysql.jdbc.Driver"); 6 conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydata?useSSL=false","root","123456"); 7//获取预编译操作对象;此时会先编译;?占位符 8 String sql="select * from t_user where loginName=? and loginPwd=?;"; 9 ps=conn.prepareStatement(sql); 10//给占位符传值 11 ps.setString(1,userInfo.get("username")); 12 ps.setString(2,userInfo.get("password")); 13//执行sql语句,因为语句不变,不会重新编译 14 res=ps.executeQuery(); 15 if (res.next()){ 16 loginSuccess=true; 17 } 18}catch(Exception e){}finally{}当业务方面要求必须使用sql注入时,必须使用Statement;比如升序降序,如果用PreparedStatement会将desc或esc加上引号,不符合逻辑
PreparedStatement增删改代码
java
sql
1package com.leiking.userlogin;
2
3import Javax.swing.plaf.nimbus.State;
4import Java.sql.*;
5import Java.util.HashMap;
6import Java.util.Map;
7import Java.util.Scanner;
8
9public class LoginMain {
10 public static void main(String[] args) {
11 //初始化界面
12 Map<String,String> userInfo=initUI();
13 //验证用户名和密码
14 boolean bol=login(userInfo);
15 //输出结果
16 System.out.println(bol==true?"登陆成功":"登陆失败");
17 }
18
19 private static boolean login(Map<String, String> userInfo) {
20 boolean loginSuccess=false;
21 Connection conn=null;
22 Statement stat=null;
23 ResultSet res=null;
24 try {
25 Class.forName("com.mysql.jdbc.Driver");
26 conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/mydata?useSSL=false");
27 stat=conn.createStatement();
28 String sql="select * from t_user where " +
29 "loginName='"+userInfo.get("username")+
30 "' and loginPwd='"+userInfo.get("password")+"';";
31 res=stat.executeQuery(sql);
32 if (res.next()){
33 loginSuccess=true;
34 }
35 return loginSuccess;
36 } catch (ClassNotFoundException e) {
37 e.printStackTrace();
38 } catch (SQLException throwables) {
39 throwables.printStackTrace();
40 }finally {
41 if (res!=null){
42 try {
43 res.close();
44 } catch (SQLException throwables) {
45 throwables.printStackTrace();
46 }
47 }
48 if (stat!=null){
49 try {
50 stat.close();
51 } catch (SQLException throwables) {
52 throwables.printStackTrace();
53 }
54 }
55 if (conn!=null){
56 try {
57 conn.close();
58 } catch (SQLException throwables) {
59 throwables.printStackTrace();
60 }
61 }
62 }
63 return true;
64 }
65
66 /**
67 * 初始化用户界面
68 * @return 用户输入的用户名与信息
69 */
70 private static Map<String, String> initUI() {
71 Scanner s=new Scanner(System.in);
72 System.out.print("输入用户名:");
73 String username=s.nextLine();
74 System.out.println();
75 System.out.print("输入密码:");
76 String password=s.nextLine();
77 System.out.println();
78 Map<String,String> userInfo=new HashMap<>();
79 userInfo.put("username",username);
80 userInfo.put("password",password);
81 return userInfo;
82 }
83}
84//sql注入现象
85//输入:用户名:fdss;密码:125' or '1'='1
86select * from t_user where loginName='fdss' and loginPwd='125' or 1 = '1单机事务 ¶
- JDBC中事务是自动提交的,执行任意一条DML语句,则会提交依次,这是JDBC默认事务行为
- conn.setAutoCommit(false):关闭事务自动提交
- conn.commit():手动提交事务
- conn.rollback():手动回滚事务;当sql语句出错时执行回滚,保证数据安全
java
1Connection conn=null;
2 PreparedStatement ps=null;
3 try {
4 //1.注册驱动
5 Class.forName("com.mysql.jdbc.Driver");
6 //2.连接数据库
7 conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/mydata","root","123456");
8 //3.获取数据库预编译操作对象
9 conn.setAutoCommit(false);//关闭事务自动提交
10 String sql="update t_act set money=? where nameno=?";
11 ps=conn.prepareStatement(sql);
12 //2001账户减钱
13 ps.setDouble(1,10000);
14 ps.setInt(2,2001);
15 ps.executeUpdate();
16 //2002账户加钱
17 ps.setDouble(1,10000);
18 ps.setInt(2,2002);
19 ps.executeUpdate();
20 conn.commit();//提交事务
21 } catch (Exception e) {
22 if(conn!=null){
23 try {
24 conn.rollback();//出错时回滚事务
25 } catch (SQLException throwables) {
26 throwables.printStackTrace();
27 }
28 }
29 e.printStackTrace();
30 }finally {//关闭连接}JDBC工具类封装 ¶
- 工具类构造方法一般为私有的,因为工具类一般调用都是静态方法
java
1public class JdbcUtil {
2 //工具类构造方法一般都是私有的
3 private JdbcUtil() {}
4 static {
5 try {
6 //静态代码块中,只要调用该类,则执行注册驱动
7 Class.forName("com.mysql.jdbc.Driver");
8 } catch (ClassNotFoundException e) {
9 e.printStackTrace();
10 }
11 }
12
13 /**
14 * 获取数据库连接对象
15 * @return 连接对象
16 */
17 public static Connection getConnection() throws Exception{
18 return DriverManager.getConnection("jdbc:mysql://localhost:3306/mydata?useSSL=false&characterEncoding=utf-8", "root", "123456");
19 }
20
21 /**
22 * 关闭资源
23 * @param conn 连接对象
24 * @param stat 数据库操作对象
25 * @param res 结果集
26 */
27 public static void close(Connection conn, Statement stat, ResultSet res){
28 if (res!=null){
29 try {
30 res.close();
31 } catch (SQLException throwables) {
32 throwables.printStackTrace();
33 }
34 }
35 if (stat!=null){
36 try {
37 stat.close();
38 } catch (SQLException throwables) {
39 throwables.printStackTrace();
40 }
41 }
42 if (conn!=null){
43 try {
44 conn.close();
45 } catch (SQLException throwables) {
46 throwables.printStackTrace();
47 }
48 }
49 }
50 public static void close(Connection conn, Statement stat){
51 if (stat!=null){
52 try {
53 stat.close();
54 } catch (SQLException throwables) {
55 throwables.printStackTrace();
56 }
57 }
58 if (conn!=null){
59 try {
60 conn.close();
61 } catch (SQLException throwables) {
62 throwables.printStackTrace();
63 }
64 }
65 }
66}