JDBC

JDBC:Java Database Connectivity  

             Java提供的一套操作数据库的标准规范(API)

             是java代码与数据库的桥梁,以一种一致的方式

             访问不同的数据库(mysql,oracle,sqlserver)

JDBC规范(掌握四个核心对象):

                       DriverManager:用于注册驱动

                       Connection: 表示与数据库创建的连接

                       Statement: 操作数据库sql语句的对象(PreparedStatement 预编译)

                       ResultSet: 结果集或一张虚拟表

      

 

开发一个JDBC程序的准备工作:

               > JDBC规范在哪里:

                      JDK中:

                             java.sql.*;

                                         java.sql.Driver 驱动(如何连接数据库)
                                         java.sql.Connection 连接(代表java程序和数据库之间连接通道)
                                         java.sql.Statement 执行sql语句
                                         java.sql.PreparedStatement
                                         java.sql.CallableStatement
                                         java.sql.ResultSet 结果集 代表的是从数据库查询结果
                                         java.sql.DriverManager 工具类,用来获取Connection
                                         java.sql.SQLException 代表执行sql过程中出现的异常

             > 数据库厂商提供的驱动:jar文件(mysql 、Oracle...)

                            *.jar

                           

 

1:使用jdbc编程的步骤(以 mysql 数据库为例)


            1) 加载驱动 (在新版的jdbc中可以省略此步骤

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


            2) 创建连接,创建Connection对象

                    String url="jdbc:mysql://localhost:3306/数据库中的库名?serverTimezone=%2B8&useSSL=false";

                    Connection  conn = DriverManager.getConnection(url,"数据库名",“数据库登录密码”);


            3) 创建Statement 对象 

                   Statement stat = conn.createStatement();

                  (  PreparedStatement stat = conn.prepareStatement(sql);  ) 可以预编译 sql 语句


            4) 执行sql语句(执行增删改或查询)

                 Statement:

                        int i = stat.executeUpdate(sql);//执行的增删改,返回值表示执行该sql语句影响的行数

                        ResultSet rs = stat.executeQuery(sql); // 执行查询的操作,返回的是一个结果集

                       boolean b = stat.execute(sql)  此方法可以执行任意sql语句。 返回boolean值,表示是否返回ResultSet结果集。                                                                            仅当执行select语句,且有返回结果时返回true, 其它语句都返回false;

                  PreparedStatement:                 

                        int i = stat.executeUpdate(); //执行的增删改,返回值表示执行该sql语句影响的行数

                        ResultSet rs = stat.executeQuery(); // 执行查询的操作,返回的是一个结果集


            5) 关闭释放资源 (由下而上依次关闭资源)

                  rs.close();

                  stat.close();

                  conn.close();

******注意:
             1> 
MySQL Connector/J 8.0.12 驱动连接时需要添加`serverTimezone=GMT%2B8`参数,否则会出现异常:                                      java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä',另外`GMT%2B8`也必须加,                                            否则会出现 连接方 和 数据库 时区不一致问题
             2> 在连接过程中一旦发生异常:java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed                       需要添加`allowPublicKeyRetrieval=true`参数,此异常一种可能的发生情况是MySQL服务重启后,立刻用jdbc连接时
             3> 出现 WARN: Establishing SSL connection without server's identity verification is not recommended                                                要消除这个警告信息,需要加入参数`useSSL=false`

2:处理ResultSet的数据:           

       封装结果集:

                  提供一个游标,默认游标指向结果集第一行之前。

                  调用一次next(),游标向下移动一行

                  提供一些getXXX() 方法。

 

       封装数据的方法

                   Object getObject(int columnIndex);  // 根据序号取值,索引从1开始

                   Object getObject(String ColomnName);  // 根据列名取值。

                   

                     boolean next()                               将光标从当前位置向下移动一行

                     int getInt(int colIndex)                    以int形式获取ResultSet结果集当前行指定列号值

                     int getInt(String colLabel)              以int形式获取ResultSet结果集当前行指定列名值

                     float getFloat(int colIndex)             以float形式获取ResultSet结果集当前行指定列号值

                     float getFloat(String colLabel)       以float形式获取ResultSet结果集当前行指定列名值

                     String getString(int colIndex)         以String 形式获取ResultSet结果集当前行指定列号值

                     String getString(String colLabel)    以String形式获取ResultSet结果集当前行指定列名

                     void close()                                    关闭ResultSet 对象

 

      将结果集中的数据封装到javaBean中

                         java的数据类型与数据库中的类型的关系

                                     byte          tinyint

                                     short         smallint

                                       int           int

                                     long          bigint

                                     float         float

                                     double        double

                                     String        char varchar

                                     Date         date

 

 3:获取表中自动增长列的值:

Statement stmt = conn.createStatement();
String sql = "insert into student(sid,sname,birthday,sex) values (null,'老炮儿','1999-1-1','男')";

//添加一个参数:               返回该自动增长列的值
stmt.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);

//获取自动增长列的值
ResultSet rs = stmt.getGeneratedKeys();

rs.next();
System.out.println(rs.getInt(1));

4:SQL注入攻击问题:

  

// 登录方法,如果有用户名和密码其中之一不正确,返回false表示登录失败
/**
 * 
 * @param username  用户输入的用户名
 * @param password  用户输入的密码
 * @return
 */
public boolean login (String username, String password) {
	Connection conn = null;
	Statement stmt = null;
	ResultSet rs = null;
	try {
		conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test3?serverTimezone=GMT%2B8&useSSL=false", "root", "123");
		stmt = conn.createStatement();
          
        //拼接SQL语句
		String sql = "select * from xx_user where username = '"+username+"' and password = '"+password+"'";

		System.out.println(sql);
		rs = stmt.executeQuery(sql);
		if(rs.next()) {
			return true;
		} else {
			return false;
		}
		
	} catch(Exception e) {
		e.printStackTrace();
		throw new RuntimeException("sql执行失败", e);
	} finally {
		if(rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if(stmt != null) {
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if(conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

   以上代码存在漏洞:        用户名和密码都没有输入正确,但返回true的例子
                    boolean success = dao.login("laowang", "aaa' or '1'='1");

                    // 相当于sql语句: select * from xx_user where ( username = 'laowang' and password = 'aaa' ) or '1'='1' ";

                   //该语句无论输入什么用户名和密码都会返回  true
           

  所以存在安全问题:解决办法: 使用 PrearedStatement 创建 statement 对象,预编译对象,避免了注入攻击问题

// 登录方法,如果有用户名和密码其中之一不正确,返回false表示登录失败
/**
 * 
 * @param username  用户输入的用户名
 * @param password  用户输入的密码
 * @return
 */
public boolean login (String username, String password) {
	Connection conn = null;
	Statement stmt = null;
	ResultSet rs = null;
	try {
	    conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test3?serverTimezone=GMT%2B8&useSSL=false", "root", "123");
    		
            // 1) 创建 PreparedStatement
            PreparedStatement stmt = conn.prepareStatement("select * from xx_user where username = ? and password = ? ");

            // 2) 给?占位符赋值
            stmt.setString(1, "laowang"); // ? 下标为 1 开始
            stmt.setString(2, "aaa' or '1'='1"); // 会将整个值当做一个整体,把or当做了值而不是关键字

            // 3) 运行sql
            ResultSet rs = stmt.executeQuery(); // 会将sql语句以及通过set方法设置的参数值,一起发送给数据库服务器

            if(rs.next()) {
	            System.out.println("查询到了");
            } else {
	            System.out.println("没查询到");
            }
	} catch(Exception e) {
		e.printStackTrace();
		throw new RuntimeException("sql执行失败", e);
	} finally {
		if(rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if(stmt != null) {
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		if(conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}



            在  PrepareStatement  对应的sql语句中,可以使用 ? 代表一个未知的值
                          1) ? 只能代表值,不能是关键字,表名,列名
                          2)调用的方法根据 ? 的实际类型而定,例如值是int 调用setInt方法
                          3) ? 的对应的set方法下标从 1 开始

5. 数据库 与Java中的 实体类 对应关系:

           1)数据库的表对应至java实体类
           2)表中的列对应实体类中的属性
           3)表中的一条记录对应至实体类的一个对象

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值