JDBC

JDBC(一堆接口):

1:在Java语句中编写sql语句,对mysql数据库中数据进行CRUD操作;

2:JDBC相关的类库?

java.sql.*;

3:这个包下都有JDBC接口,JDBC是体现“接口作用”非常经典的例子。JDBC降低耦合度,提升扩展力,只要面向JDBC接口编程接口。

 

2:JDBC编程六部步:*非常重要重点就在这

1:注册驱动(通过java程序我们即将连接那个品牌数据库);

2:获取数据库连接(将两个进程的通过开启);

3:获取数据库操作对象(用这个对象进行sql);

4:执行sql语句(执行RUL);

5 : 处理查询结果集(如果第四步select 语句,才有这个第五步);

6:释放资源(关闭所有资源因为DBC毕竟是进程之间的通信,占很多资源,需要关闭!)。

 

3:URL(统一资源定位符):

1:任何一个URL都包括:http://192.168.100.2:8888/abc

2:协议:一个提前规定好的数据传输方式,通信有http:https;

在传数据之前,提前先商量好数据传送的格式,对方接收到数据之后,就按照这个去解析,拿到有价值的数据。

3:jdbc:mysql:// 这是java与mysql通信的协议

localhost 本机IP地址,本机IP地址也可127.0.0.1

3306 mysql数据库端口号

bjpowernode mysql数据库的名称

(jdbc:mysql://localhost:3306/bjpowernode)

4 :oracle数据库:

oracle:jdbc:thin:@ oracle和java的通信协议

localhost 本机IP地址

1521 oracle默认端口

bjpowernode oracle中数据库名字

(oracle:jdbc:thin:@localhost:1521:bjpowernode)

 

4:JDBC编程六步:

public class JDBC{

public static void main(String[] args){

Connectioon conn = null;

Statement stmt = null;

ResultSet rs = null;

1:加载驱动

DriverManager.registerDriver(new.mysql.jdbc.Driver);

Class.forName(com.mysql.jdbc.Driver);

2: 获取数据库对象

conn=DriverManager.getConnection("jdbcmysql://localhost:3306/bjpowernode") ;

3:获取数据库操作对象

stmt = conn.creatStatement();

4:执行sql语句(JDBC不用;结尾)

String sql = "select empno,ename,sal from emp order by sal desc";

5:处理查询结果集

while(rs.next()){

String ename = rs.getString("ename");

String dname = rs.getString("dname");

System.out.println(ename+","+dname);

}catch (SQLExcption e){

e.printStackTrace();

}finally {

6:释放资源

if(conn != null){

try{

conn.close();

}catch (SQLExcption e){

e.printStackTrace();

}

}

if(stmt != null){

try{

stmt.close();

}catch (SQLExcption e){

e.printStackTrace();

}

}

if(rs != null){

try{

rs.close();

}catch (SQLExcption e){

e.printStackTrace();

}

}

}

}

}

 

5:读取属性配置文件:

1: 思考:将连接的数据库的可改变的4条写到配置文件中,以后想;连接其他数据库时,可直接修改配置文件,不可修改java程序。

(四个信息为:driver,url ,user,password)

2:在原有的JDBC的程序加一个属性配置文件,在加一个资源绑定器。

ResourceBundlebundle=ResourceBundle.getBundle("resources/db")

//通过属性配置文件拿到信息

String driver = bundle.getString ("driver");

String url = bundle.getString ("url");

String user = bundle.getString ("user");

String password = bundle.getString("password");

System.out.println(driver);

System.out.println(url);

System.out.println(user);

System.out.println(password);

(这样的话可以直接在Java文件中写这四个信息)

 

6:mysql和oracle的四大信息:

 

######mysql  cnnectivity  connfiguration########
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/bjpowernode
user=root
password=123456



#######oracle  cnnectivity  connfiguration########
#driver=oracle.jdbc.driver.OracleDriver
#url=jdbc:oracle:thin@localhost:1521:bjpowernode
#user=scott
#password=tiger

 

7:SQL注入:

以上随意输入一个用户名和密码,登陆成功,被称为SQL注入现象。

导致:SQL注入的根本原因是什么?怎么解决?

根本原因:用户名不是一般用户,用户懂程序,输入用户名信息以及密码信息中含有SQL语句关键字,这个SQL语句的关键字和底层的SQL进行“字符串拼接”,导致原SQL语句的含有被扭曲。

最最最最最主要因素:这个程序先进行字符串连接,然后再进行SQL语句编译,正好被注入。

"select * from t_user where login_name = "'+loginName+'" and login_pwd =" '+loginPwd+'";

 

8:怎么避免SQL注入:

public class JDBCTest02 {
   public static void main(String[] args) {
       Map<String, String> userLoginInfo = initUI();

       boolean ok = checkNameAndPwd(userLoginInfo.get("loginName"), userLoginInfo.get("loginPwd"));

       System.out.println(ok ? "登录成功" : "登录失败");

  }

   private static boolean checkNameAndPwd(String loginName, String loginPwd) {
       boolean ok = false;
       Connection conn = null;
       PreparedStatement stmt = null;
       ResultSet rs = null;
       try {
           Class.forName("com.mysql.jdbc.Driver");
           conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode", "root", "123456");
           String sql = "select * from t_user where login_name=? and loginPwd = ?";
           stmt = conn.prepareStatement(sql);
           stmt.setString(1, loginName);
           stmt.setString(2, loginPwd);
           rs = stmt.executeQuery();
           if (rs.next()) {
               ok = true;
          }

          } catch(Exception e){
               e.printStackTrace();
          } finally{
               if (rs != null) {
                   try {
                       rs.close();
                  } catch (SQLException throwables) {
                       throwables.printStackTrace();
                  }
              }
               if (stmt != null) {
                   try {
                       stmt.close();
                  } catch (SQLException throwables) {
                       throwables.printStackTrace();
                  }
              }
               if (conn != null) {
                   try {
                       conn.close();
                  } catch (SQLException throwables) {
                       throwables.printStackTrace();
                  }
              }
          }
       return true;
      }
   private static Map<String, String> initUI() {
       System.out.println("欢迎进入");
       Scanner s = new Scanner(System.in);
       System.out.println("用户名:");
       String loginName  = s.nextLine();
       System.out.println("密码:");
       String loginPwd = s.nextLine();

       Map<String,String> userloginInfo = new HashMap<>();
       userloginInfo.put("loginName",loginName);
       userloginInfo.put("loginPwd",loginPwd);

       return userloginInfo;
  }

}

 

8:Statement接口特点和PreparedStatment接口特点:

java.sql.Statement接口特点:先进行字符串的拼接,然后SQL编译,

优点:使用Statement可以进行sql语句拼接

缺点:拼接的存在,导致可能有不法分子SQL注入。

java.sql.PreparedStatement接口特点:先进行SQL编译,然后给值,

优点:避免SQL注入

缺点:没有办法进行SQL语句拼接,只能给sql传值。

 

9:PreparedStamtement代码:只能传值

public class JDBCPreparedStatement {
   public static void main(String[] args) {
       Scanner s = new Scanner(System.in);
       System.out.print("请输入desc或asc【desc为降序,asc为升序】:");
       String orderKey = s.next();

       Connection conn = null;
       PreparedStatement ps = null;
       ResultSet rs = null;

       try {
           //1,加载驱动
           Class.forName("com.mysql.cj.jdbc.Driver");
           //2,获取连接
           conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode", "root", "123456");
           //3,获取预编译的数据库对象
           String sql= "select ename,sal from emp order by sal ?";
           ps = conn.prepareStatement(sql);
           ps.setString(1,orderKey);
           //执行sql语句
           rs = ps.executeQuery();
           while (rs.next()){
               String ename = rs.getString("ename");
               String sal = rs.getString("sal");
               System.out.println(ename +","+ sal);
          }
      } catch (Exception e) {
           e.printStackTrace();
      }finally {
           if (rs != null) {
               try {
                   rs.close();
              } catch (SQLException throwables) {
                   throwables.printStackTrace();
              }
          }
           if (ps != null) {
               try {
                   ps.close();
              } catch (SQLException throwables) {
                   throwables.printStackTrace();
              }
          }
           if (conn != null) {
               try {
                   conn.close();
              } catch (SQLException throwables) {
                   throwables.printStackTrace();
              }
          }
      }
  }
}

 

10:Statement代码场景:

public class JDBCStatement {
   public static void main(String[] args) {
       Scanner s = new Scanner(System.in);
       System.out.print("请输入desc或asc【desc为降序,asc为升序】:");
       String orderKey = s.next();

       Connection conn = null;
       Statement ps = null;
       ResultSet rs = null;

       try {
           //1,加载驱动
           Class.forName("com.mysql.cj.jdbc.Driver");
           //2,获取连接
           conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode", "root", "123456");
           ps = conn.createStatement();
           //3,获取预编译的数据库对象
           String sql= "select ename,sal from emp order by sal " + orderKey;
           //执行sql语句
           rs = ps.executeQuery(sql);
           while (rs.next()){
               String ename = rs.getString("ename");
               String sal = rs.getString("sal");
               System.out.println(ename +","+ sal);
          }
      } catch (Exception e) {
           e.printStackTrace();
      }finally {
           if (rs != null) {
               try {
                   rs.close();
              } catch (SQLException throwables) {
                   throwables.printStackTrace();
              }
          }
           if (ps != null) {
               try {
                   ps.close();
              } catch (SQLException throwables) {
                   throwables.printStackTrace();
              }
          }
           if (conn != null) {
               try {
                   conn.close();
              } catch (SQLException throwables) {
                   throwables.printStackTrace();
              }
          }
      }
  }
}

 

11:PreparedStatement完成增删改:

 

public class PreparedStatementZengShanGai {
   public static void main(String[] args) {


       Connection conn = null;
       PreparedStatement ps = null;

       try {
           //1:加载驱动
           Class.forName("com.mysql.cj.jdbc.Driver");
           //2:获取连接
           conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode", "root", "123456");
           //3:获取预编译数据库对象
           String sql = "insert into dept(deptno,dname,loc) values (?,?,?)";
           ps = conn.prepareStatement(sql);
           //给?传值
           ps.setInt(1, 50);
           ps.setString(2, "YLC");
           ps.setString(3, "pingjiang");

           String sql1 = "update dept set dname = ?,loc = ? where deptno = ?";
           ps = conn.prepareStatement(sql1);
           //给?传值
           ps.setString(2, "YLCandZY");
           ps.setString(3, "pingjiangzy");
           ps.setInt(3, 50);

           //5:执行sql语句
           int count = ps.getUpdateCount();
           System.out.println(count);
      } catch (Exception e) {
           e.printStackTrace();
      } finally {
           if (ps != null) {
               try {
                   ps.close();
              } catch (SQLException throwables) {
                   throwables.printStackTrace();
              }
          }
           if (conn != null) {
               try {
                   conn.close();
              } catch (SQLException throwables) {
                   throwables.printStackTrace();
              }
          }
      }
  }
}

 

12:模糊查询:(?不能出现在单引号中)

 

public class JDBCMoHu {
   public static void main(String[] args) {
       Connection conn = null;
       PreparedStatement ps = null;
       ResultSet rs = null;

       try {
           //1:
           Class.forName("com.mysql.cj.jdbc.Driver");
           //
           conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","123456");
           //
           String sql = "select ename from emp where ename like ?";
           ps = conn.prepareStatement(sql);
           ps.setString(1,"%O%");

           //执行SQL语句
           rs = ps.executeQuery();
           while (rs.next()){
               System.out.println(rs.getString("ename"));
          }
      } catch (Exception e) {
           e.printStackTrace();
      }finally {
           if (rs != null) {
               try {
                   rs.close();
              } catch (SQLException throwables) {
                   throwables.printStackTrace();
              }
          }
           if (ps != null) {
               try {
                   ps.close();
              } catch (SQLException throwables) {
                   throwables.printStackTrace();
              }
          }
           if (conn != null) {
               try {
                   conn.close();
              } catch (SQLException throwables) {
                   throwables.printStackTrace();
              }
          }
      }


  }
}

 

13:JDBC事务:

JDBC默认情况自动提交?

只要执行一条DML语句就提交一次

在实际开发中必须将JDBC的自动提交关闭,改为手动提交;

(因为这样的话即使出现错误,数据也不会丢失)。

conn.setAutCommit(false);关闭自动提交机制;

conn.commit()手动提交;

conn.rollback();手动回滚

public class JDBCShiWu {
   public static void main(String[] args) {
       Connection conn = null;
       PreparedStatement ps = null;
       try {
           //1,加载驱动
           Class.forName("com.mysql.cj.jdbc.Driver");
           //获取连接
           conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","123456");
           conn.setAutoCommit(false);
           //获取预编译数据库对象
           String sql = "update t_act set balance = ? where actno = ?";
           ps = conn.prepareStatement(sql);

           //给?值
           ps.setDouble(1,10000);
           ps.setString(2,"A");
           int count =  ps.executeUpdate();

           //Thread.sleep(100*10);
           String s = null;
           s.toString();

           ps.setDouble(1,10000);
           ps.setString(2,"B");
           count += ps.executeUpdate();

           System.out.println(count == 2 ? "成功":"失败");

           //手动提交,事务结束
           conn.commit();
      } catch (Exception e) {
           //为保险起见,要回滚
           try {
               if (conn != null) {
                   conn.rollback();
              }

          } catch (SQLException throwables) {
               throwables.printStackTrace();
          }
           e.printStackTrace();
      }finally {
           if (conn != null) {
               try {
                   conn.close();
              } catch (SQLException throwables) {
                   throwables.printStackTrace();
              }
          }
      }
       if (ps != null) {
           try {
               ps.close();
          } catch (SQLException throwables) {
               throwables.printStackTrace();
          }
      }
  }
}

 

14:JDBC工具类的封装(降低耦合度,提升扩展力):

为保级加载驱动在类加载时执行,只执行一次

静态代码块 static{ }

public class JDBCFenZhuang {
   //工具类的构造方法一般都是私有化的
   //构造方法私有化是为了防止new对象,为什么防止new对象?
   //因为工具类中方法都是静态的,不需要new对象,直接用类名的方式调用

   private void DBUtil(){}

   //类加载是绑定属性资源文件
   private static ResourceBundle bundle = ResourceBundle.getBundle("resources/db");

   //注册驱动
   static {
       try {
           Class.forName(bundle.getString("driver"));
      } catch (ClassNotFoundException e) {
           e.printStackTrace();
      }
  }
   public static Connection getConnection() throws SQLException{
       String url = bundle.getString("url");
       String user = bundle.getString("user");
       String password = bundle.getString("password");
       Connection conn = DriverManager.getConnection(url,user,password);
       return conn;
  }
   public static void close(Connection conn, Statement stmt, ResultSet rs){
       if (conn != null) {
           try {
               conn.close();
          } catch (SQLException throwables) {
               throwables.printStackTrace();
          }
      }
       if (stmt != null) {
           try {
               stmt.close();
          } catch (SQLException throwables) {
               throwables.printStackTrace();
          }
      }
       if (rs != null) {
           try {
               rs.close();
          } catch (SQLException throwables) {
               throwables.printStackTrace();
          }
      }
  }
  }

 

15:测试封装类工具:

public class JDBCTestDBUtil {
   public static void main(String[] args) {
       Connection conn = null;
       PreparedStatement ps  = null;
       ResultSet rs = null;

       try {
           //1 获取连接
            conn = JDBCFenZhuang.getConnection();
           //2 获取预编译的数据库操作对象
           String sql = "select ename,sal from emp where ename like ?";
           ps = conn.prepareStatement(sql);
           //给?传值
           ps.setString(1,"A%");
           //执行sql
           rs = ps.executeQuery();
           //处理结果集
           while (rs.next()){
               System.out.println(rs.getString("ename")+","+rs.getString("sal"));
          }
      } catch (SQLException throwables) {
           throwables.printStackTrace();
      }finally {
           JDBCFenZhuang.close(conn,ps,rs);
      }
  }
}

 

16:行级锁(for update):

当使用select ...where.....for update ,mysql进行row lock还是table lock只取决于是否使用索引(列如主键,unique字段)能则为行锁,否则为表锁,未查到数据则为无锁,而使用'<>','like'等操作,索引会失效,自然进行是table lock 所以慎用for update。

整个表锁住的时候会导致性能降低,谨慎使用使用for update的时候,最好是锁主锁值,或具是unique约束字段,锁别的字段导致整个表锁住。

posted on 2021-05-07 23:29  只想做加法(ylc)  阅读(147)  评论(0)    收藏  举报

导航