JDBC技术(一)JDBC基础入门

JDBC概述:

Java DataBase Connectivity Java数据库的连接。

  1. 目的使用Java的代码来操作数据库
  2. 需要使用JDBC(Java数据库的连接)规范来操作数据

JDBC规范:

  1. JDBC是一套接口规范,为访问不同的数据库提供了一种统一的途径。
  2. JDBC的实现类都是由各个数据库的生产商来提供的

驱动:

  1. 它是数据传输的桥梁
  2. 驱动指的是各个数据库生产商提供的实现类 (比如我们操作mysql的数据库就需要导入mysql的驱动包)

JDBC相关的接口和API介绍:

  1. java.sql.DriverManager用来管理JDBC的驱动的实现类。
  2. java.sql.Connection完成对某一指定数据库的联接。
  3. java.sql.Statement在一个给定的连接中作为SQL执行声明的容器。
  4. java.sql.ResultSet对于给定声明取得结果的途径。

下面用来写一个简单的入门程序,以查询操作为例,大致分为如下几个步骤:

准备工作:建库建表。

  1. 加载驱动类(必须预先导入jar包)
  2. 取得连接
  3. 执行一些sql语句(此处执行查询语句)
  4. 遍历结果集(查询到的数据会封装到结果集中)
  5. 释放资源

代码示例:

public class Test1 {

	public static void main(String[] args) {
		Connection conn = null;
		ResultSet rs = null;
		Statement state = null;
		try {
			//1   加载mysql驱动类----方式一:这种方式一般不用
//			DriverManager.registerDriver(new Driver());
			//方式二
			Class.forName("com.mysql.jdbc.Driver");
			
			//2   获取连接
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo",
					"root", "root");
			
			//3 执行sql语句
			String sql = "select * from t_user";
			//不要用这种方式
			state = conn.createStatement();
			rs = state.executeQuery(sql);
			
			//4 遍历结果集
			while(rs.next()) {
				int id = rs.getInt("id");
				String userName = rs.getString("username");
				String password = rs.getString("password");
				String email = rs.getString("email");
				
				System.out.println(id + "  " + userName + "   " + password + "   " + email);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//释放资源
			if(rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if(state != null) {
				try {
					state.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if(conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}

}

输出结果:

 

来简单分析一下上述代码:

一、加载驱动类

有两种方式:第一种需要实例化一个Driver对象。  第二种方式是利用全限定名来直接加在该类的.class文件。

第一种方式一般是不用的,我们来看一下Driver这个类的源码:

public class Driver extends NonRegisteringDriver implements java.sql.Driver {

    static {
        try {
	    java.sql.DriverManager.registerDriver(new Driver());
	} catch (SQLException E) {
	    throw new RuntimeException("Can't register driver!");
	}
    }
		
    public Driver() throws SQLException {}

}

首先确实可以看到该类是java.sql.Driver的实现类。再者该类中的静态代码块中已经帮我们做了方式一的操作了。那我们就不用再重复进行了。静态块中的内容是伴随着类的加载过程(初始化阶段)执行的,所以我们只需要将该类加载进来就可以了。所以可以用方式二加载驱动。而且方式二是传一个字符串参数值。那就可以通过读取外部配置来加载。这样我们只需要修改配置文件就可以修改相关内容。

 二、获取连接:可以用上述方法获取连接,需要传入数据库服务器的URL,账号,密码。

下面列举几个常见数据库的URL:

  1. Oracle 数据库:jdbc:oracle:thin:@localhost:1521:xxx
  2. SQLServer 数据库:jdbc:microsoft:sqlserver//localhost:1433; DatabaseName=xxx
  3. MYSQL 数据库:jdbc:mysql://localhost:3306/xxx

以mysql的url为例:

其中jdbc代表主协议,mysql为子协议,localhost:3306子名称(数据库服务器地址)如果访问的是本机的数据库,此处可以省略不写,xxx你建立的数据库名称。

对于上述代码,直接将这三个参数值写死,很明显不好。这块也可以改为可配置的方式。当然还可以采用数据库连接池的方式来获取连接。

三、执行sql语句

  1. 创造sql语句例如此处的select * from t_user;
  2. 接着执行查询命令。可用executeQuery方法。

不过上述代码中的方式存在sql注入的问题,比如将上述sql语句稍微变一下:

select * from t_user where username='zhang' or 1=1 and  password='你看我出不出来'

执行结果:

他竟然获取到了。。。如果将动态的username和password参数值按照上述方式拼接就可以获取到那还是比较害怕的,显然是不好,不是我们想要的结果。

其实上述sql语句主要能执行成功是因为有or这个关键字  因为前面username=‘zhang’ 这个是正确的,and优先级高于or,先执行and,故后面一串  1=1 and password=‘你看我出不出来’  这个整体上为false。只不过username为真,那后面的就被短路了。

我们可以再变一下sql语句:select * from t_user where username='zhang' or '无所谓了'  结果依然能够获取到数据。而且不仅仅是这个问题。如果要批量查询多条数据,这种方式就是存在大量的字符串拼凑!效率也不好。 

解决方法

对于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement 取代 Statement 就可以了。PreparedStatement接口,是Statement的子接口。其有预编译的功能,可以把SQL语句中的参数的部分使用?(占位符)来代替,他是先将编写的SQL语句发送到MySQL服务器端,然后对这条SQL语句进行编译,编译后的SQL语句的格式就是固定的了,再传入任何的值,都会做?的参数来出现。我们可以利用 conn.prepareStatement(String sql)方法对sql语句进行预编译。然后利用 PreparedStatement接口提供的各种setXXX(...)方法填充占位符即可。

代码展示如下:

public class Test1 {

	public static void main(String[] args) {
		Test1.getUser("zhang or 1=1", "234242");
	}

	public static void getUser(String userName, String password) {
		Connection conn = null;
		ResultSet rs = null;
		PreparedStatement state = null;
		
		try {
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo",
					"root", "root");
			String sql = "select * from t_user where username=? and password=?";
			//执行sql预编译
			state = conn.prepareStatement(sql);
			//索引是从1开始的,填充占位符
			state.setString(1, userName);
			state.setString(2, password);
			
			rs = state.executeQuery();
			
			if(!rs.next()) {
				System.out.println("没获取到哦");
			}
			while(rs.next()) {
				int id = rs.getInt("id");
				String name = rs.getString("username");
				String psw = rs.getString("password");
				String email = rs.getString("email");
				System.out.println(id + "  " + name + "   " + psw + "   " + email);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			//关闭资源
		}
		
	}
}

执行结果:

 

四、获取结果:

当我们获取到数据时,比如上述所有字段包括id,username,password,email。很显然可以将上述内容封装到一个User对象中。

上述就是我对这些知识的一些粗浅理解。接下来的文章会继续分享。

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值