用JDBC于数据库交互

1.用JDBC于数据库交互

1.1JDBC简介

	JDBC(Java Data Base Connectivity)是一种用于执行SQL语句的JavaAPI,它由一组用于Java语言编写的类和接口组成。JDBC为数据库开发人员提供了一个标准的API,使用这套API可以跨平台运行,并且不受数据库供应商的限制。
	跨平台运行继承了Java语言“一次编译,到处运行”的特点。
	不受数据库供应商的限制:JDBC设有两种接口;一个是面向应用程序员,使得开发人员通过SQL调用数据库;
	另一个是驱动程序员,JDBC驱动程序可以利用JDBCAPI是的Java可以方便地操作数据库底层。应用程序只需要编写一次,便可以移到各种驱动程序上运行。

1.2JDBC驱动程序原理

为了是客户端程序独立于特定的数据库驱动程序,JDBC规范建议开发者使用基于接连的编程方式,即尽量使应用仅依赖Java.sql及Javax.sql中的接口和类。

上图是Java访问数据库的原理,可以看出,客户端程序调用Java.sql包下面的API,Java.sql下的API调用相应驱动程序,而相应的驱动程序调用相应的数据库,从而完成数据库的操作。

2.Java与MySQL数据库的连接

Java连接MySQL数据库可以用如下几大步骤:
  1. 加载驱动程序——在开发环境中加载指定数据库的驱动程序
  2. 创建数据连接对象——通过DriverManager类创建数据库连接对象Connection。DriverManager类作用于加Java程序和JDBC驱动之间,用于检查所加载的驱动程序是否可以连接,然后通过它的getConnection方法,根据数据库的URL、用户名和密码,创建一个JDBCConnection对象:
    Connection connection = DriverManager.getConnection("URL","用户名","密码");
    其中,URL=协议名+IP地址(域名)+端口+数据库名称;例如:
    Connection conn =  DriverManager.getConnection("jdbc:mysql://localhonst:3306/mytest", "root", "123456");

  3. 创建Statement对象
    Statement类的主要是用于执行静态SQL语句并返回它所生产结果的对象。通过Connection对象的createStatement()方法可以创建一个Statement对象。
    Statement statement = conn.createStatement();

  4. 调用Statement对象的相关方法执行相应的SQL语句。
    通过executeUpdate()方法用来数据更新,包括插入和登出等。
    statement.executeUpdate("insert into t_person(name,age)values('sss',28)");
    通过调用Statement对象的executeQuery()方法进行数据的查询,而查询结果会得到ResulSet对象,ResulSet表示执行查询数据库后返回的集合,ResulSet对象具有可以指向当前数据行的指针。通过该对象的next()方法,是的指针指向下一行,然后将数据以列号或字段名取出,如果当前next()方法返回null,则表示下一行中没有数据存在。例如:
    ResultSet resultSet = statement.executeQuery("select * from t_person");

  5. 关闭数据库连接
    使用完数据库或不需要访问数据库时,通过Connection的close()方法及时关闭数据连接。

3.查询数据库和结果集

ResultSet类的常见方法见API
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

public class QueryTest {
	public static void main(String[] args) throws SQLException, ClassNotFoundException {
		//连接数据库的url
		String url = "jdbc:mysql://localhost:3306/mytest";
		//数据库用户名
		String user = "root";
		//数据库密码
		String password = "mysql1991";
		//1加载驱动
		Class.forName("com.mysql.jdbc.Driver");
		//2创建数据连接对象
		Connection conn =  DriverManager.getConnection(url, user, password);
		//3.创建Statement对象
		Statement statement = conn.createStatement();
		//4.获取ResultSet对象
		String sql = "select name,age from t_person";
		ResultSet rs = statement.executeQuery(sql);
		while (rs.next()) {//判断是否有下一个
			//获取字段name数据
			String name = rs.getString("name");
			//获取字段age数据
			int age = rs.getInt("age");
			System.out.println("姓名:"+name+"  年龄:"+age+"岁");
		}
		//5.关闭数据库
		//注意关闭顺序
		rs.close();
		statement.cancel();
		conn.close();
	}
通常在实际开发中,都会建立一个类将表中的字段封装到该类的属性中,通常类名即表名,类的各属性代表表中的各字段。
对于数据库关闭,最好先关闭ResultSet对象,然后关闭Statement对象,最好才是Connection对象,并且建议关闭操作放在finally块进行,在关闭前还应当进行非空判断。
*
 * 封装类
 */
public class Person {
	private int id;
	private String name;
	private int age;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "序号:"+id+" 姓名:"+name+"  年龄:"+age+"岁";
	}
}
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

public class QueryTest {
	public static void main(String[] args) {
		List<Person> lists = new QueryTest().findAll();
		for (Person person : lists) {
			System.out.println(person);
		}
	}

	private List<Person> findAll() {
		Connection conn = null;
		Statement statement = null;
		ResultSet rs = null;
		List<Person> lists = new ArrayList<Person>();
		// 连接数据库的url
		String url = "jdbc:mysql://localhost:3306/mytest";
		// 数据库用户名
		String user = "root";
		// 数据库密码
		String password = "mysql1991";
		try {
			// 1加载驱动
			Class.forName("com.mysql.jdbc.Driver");
			// 2创建数据连接对象
			conn = DriverManager.getConnection(url, user, password);
			// 3.创建Statement对象
			statement = conn.createStatement();
			// 4.获取ResultSet对象
			String sql = "select * from t_person";
			rs = statement.executeQuery(sql);
			while (rs.next()) {// 判断是否有下一个
				Person p = new Person();
				// 获取字段name数据
				String name = rs.getString("name");
				p.setName(name);
				// 获取字段age数据
				int age = rs.getInt("age");
				p.setAge(age);
				p.setId(rs.getInt("id"));
				lists.add(p);
				// System.out.println("姓名:" + name + "  年龄:" + age + "岁");
			}
		} catch (ClassNotFoundException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		} finally {
			// 5.关闭数据库
			// 注意关闭顺序
			try {
				if (rs != null)
					rs.close();
				if (statement != null)
					statement.cancel();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
		}
		return lists;
	}
}

4.更新删除数据

	修改数据操作使用的的是Statement对象的executeUpdate(sql)方法,该方法返回的是一个整数,整数的大小意味着有多少条数据执行。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

/*
 * 更改数据库数据
 */
public class InsertTest {
	public static void main(String[] args) {
		InsertTest it = new InsertTest();
		Person p = new Person();
		p.setName("唐老鸭");
		p.setAge(22);
		it.insert(p);
	}

	private void insert(Person p) {
		Connection conn = null;
		Statement stmt = null;
		// 连接数据库url
		// String url =
		// "jdbc:mysql://localhost:3306/mytest?useUnicode=true&characterEncoding=UTF-8";
		String url = "jdbc:mysql://localhost:3306/mytest?useUnicode=true&characterEncoding=UTF-8";
		// 数据库用户名
		String user = "root";
		// 数据库密码
		String password = "mysql1991";
		try {
			// 1.加载驱动
			Class.forName("com.mysql.jdbc.Driver");
			// 2.创建数据连接对象
			conn = DriverManager.getConnection(url, user, password);
			// 3.创建Statement对象
			stmt = conn.createStatement();
			// 对sql拼接
			String sql = "insert into t_person(name,age)values('" + p.getName()
					+ "','" + p.getAge() + "')";
			// 执行增加操作
			int c = stmt.executeUpdate(sql);
			if (c > 0) {
				System.out.println("增加了" + c + "条数据!");
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {// 关闭数据库
				if (stmt != null)
					stmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

下面一段是摘抄自http://blog.csdn.net/wuzuyu365/article/details/51478063
连接MySQL数据库的时候一般都会在url后面添加useUnicode=true&characterEncoding=UTF-8 
添加的作用是:指定字符的编码、解码格式。
             例如:MySQL数据库用的是gbk编码,而项目数据库用的是utf-8编码。这时候如果添加了useUnicode=true&characterEncoding=UTF-8 ,那么作用有如下两个方面:
1. 存数据时:
     数据库在存放项目数据的时候会先用UTF-8格式将数据解码成字节码,然后再将解码后的字节码重新使用GBK编码存放到数据库中。
2.取数据时:
     在从数据库中取数据的时候,数据库会先将数据库中的数据按GBK格式解码成字节码,然后再将解码后的字节码重新UTF-8格式编码数据,最后再将数据返回给客户端。
注意:在xml配置文件中配置数据库utl时,要使用&的转义字符也就是&amp;
      例如:<property name="url" value="jdbc:mysql://localhost:3306/email?useUnicode=true&amp;characterEncoding=UTF-8" />

5.PreparedStatement对象的使用

preparedStatement的功能呢与Statement的功能类似,主要体现在:

  • 使用preparedStatement可以防止SQL注入
  • 使用preparedStatement传入参数更简单
SQL注入是利用现有应用程序,将恶意的SQL命令注入到后台数据库引擎执行的能力,通常主要应用在某些用户不需要知道密码,就可以登录某系统。

	SQL注入的命令代码:select *from t_user where name='sky'and password=' ' or  1='1';
	从这段代码可以看出即使不知道密码,也能得到数据,这是因为关键字or起作用,只要满足一个条件就可以,而1=‘1’这个绝对满足,所以无论用户名和密码是什么,都会返回数据。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;


/*
 * 简单模拟SQL注入
 */
public class SQLTest {
	public static void main(String[] args) {
		String name = "sky";
		String password = " ' or 1='1'" ;//拼接,从而通过数据库的检查
		new SQLTest().mysql(name, password);
	}


	private void mysql(String name, String password) {
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		//用户名
		String userName="root";
		//密码
		String psw = "mysql1991";
		// 连接数据库的url
		String url = "jdbc:mysql://localhost:3306/mytest";
		
		try {// 1.加载驱动
			Class.forName("com.mysql.jdbc.Driver");
			//2.创建 数据库 连接对象
			conn = DriverManager.getConnection(url,userName,psw);
			// 3创建Statement对象
			stmt = conn.createStatement();
			// SQL语句
			String sql = "select * from t_user where name='" + name
					+ "'and password='" + password;
			//4 获取ResultSet对象
			rs = stmt.executeQuery(sql);
			while (rs.next()) {
				System.out.println("用户名:" + rs.getString("name") + "  密码:"
						+ rs.getString("password"));
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if (rs != null)
					rs.close();
				if (stmt != null)
					stmt.close();
				if (conn != null)
					conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}


上例可以看出在不知道密码的情况下,也可以登录成功。为了杜绝SQL注入,就必须采用PreparedStatement对象,PreparedStatement是从Java.sql.connection对象提供的SQL字符串得到的,SQL字符串中包含问号(?),这些问号表明变量的位置,然后提供变量的值,最后执行语句。例如:
sql = "select * from t_user where name=? and password=?";
PreparedStatement ps = conn.PreparedStatement(sql);
ps.setString(1,name);
ps.setString(2,password);
ResultSet rs = ps.executeQuery();
把上面的第3和4两部分改一下就好:
String sql2 = "select * from t_user where name=? and password=?";
			PreparedStatement pstmt = conn.prepareStatement(sql2);
			pstmt.setString(1, name);
			pstmt.setString(2, password);
			rs=pstmt.executeQuery();
			if (rs.next()) {
				System.out.println("用户名:" + rs.getString("name") + "  密码:"
						+ rs.getString("password"));
				System.out.println("登录成功");
			}else {
				System.out.println("登录失败");
			}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值