JDBC基础使用

我们为什么需要JDBC?

  任何一款程序,都是在与数据交互的基础上运行的。而有些数据,我们需要持久化得保存起来,所以我们使用了各类数据库,如Mysql、Oracle等。这些数据库,就可以看作是一款单独的程序软件,那么我们编写的Java代码,如何与数据库进行交互呢?

  程序与程序的交互,本质上就是进行通讯,JDBC(JAVA Database Connectivity)就是这个通讯的桥梁。SUN公司在Java中提供了接口,然后靠各个数据库厂商实现接口,我们也常把这些实现称作驱动包。通过这种面向接口编程的方式,JAVA程序与不同的数据库交互,只需要使用不同的驱动包即可,主体逻辑不需要大型改动。

  下面主要以Mysql数据库为例,介绍JDBC的使用。

第一步:加载驱动

  首先获得数据库的驱动jar包,并导入工程。

  在编程中要连接数据库,还要先加载数据库驱动程序。不同的数据库有不同的装载方法,但一般都是通过Class类来加载:

		//加载Mysql数据库驱动
		try {
			Class.forName("com.mysql.jdbc.Driver");//路径名是固定的
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		//加载Mysql数据库驱动	
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");//路径名是固定的
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

第二步:获取连接对象

  有了接口的实现驱动后,我们需要创建一个连接对象(万物皆对象嘛)来进行通讯的操作。

  Java中为连接对象定义了Connection接口,通过DriverManager接口来得到Connection对象:

		String url = "jdbc:mysql://localhost:3306/mydb";
		//Oracle的url格式为:jdbc:oracle:thin:@host:port:databse
		String user = "root";
		String password = "1234";
		
		try {
			Connection conn =DriverManager.getConnection(url,user,password);
		} catch (SQLException e) {
			e.printStackTrace();
		}

  建立连接的过程,包含了许多步骤,包括通讯的建立、登陆身份验证等,所以此步骤是非常耗时的。而且如果每交互一次就获取一个连接对象,交互完成后立马关闭对象,这样的设计明显非常低效。所以我们一般使用连接池的方式管理连接对象。关于连接池,可以看我的这篇博客:《连接池与DBCP、Druid》

第三步:获取SQL执行对象

  有了连接Connection对象后,说明已可以与数据库正常通讯,信道已打开。这时候我们希望传sql语句给数据库执行的话,不是使用连接对象直接执行,而是需要创建Statement语句对象,用来执行sql语句。

  Statement可以分为三类:

  • Statement,使用createStatement()方法创建,sql语句由字符串拼接而成。
  • PreparedStatement,使用prepareStatement()方法创建,可以使用?占位符来表示输入参数,可以有效防止sql注入。
  • CallableStatement,使用prepareCall()方法创建,继承自PreparedStatement,用于调用存储过程。

  三种获取SQL执行对象的代码实例:

		String sql = "";
		Statement stmt1 = conn.createStatement();//创建时不需要sql,执行时才传入
		Statement stmt2 = conn.prepareStatement(sql);//创建时需要sql,参数定义完成后直接执行
		Statement stmt3 = conn.prepareCall(sql);

第四步:执行SQL语句

  得到Statement对象后,则可以开始编写sql语句来进行执行。不用的语句有不同的执行过程,但都是使用以下三个方法来执行:

  • execute():运行语句,返回是否有结果集
  • executeQuery():运行select语句,返回ResultSet结果集。
  • executeUpdate():运行insert/update/delete操作,返回更新的行数。

下列实例中用到的t_student表结构为:
在这里插入图片描述

DML语句

  使用Statement执行DML语句:

		Statement stmt1 = conn.createStatement();
		String name = "小猪";
		int age = 18;
		Date date = new Date(System.currentTimeMillis());
		//拼接sql
		String sql = "insert into t_student (name,age,birthday) "
				+ "values ('" + name + "'," + age + ",'"+ date +"')";//让人眼花的拼接
		//使用execute执行
		stmt1.execute(sql);

  使用prepareStatement执行DML语句:

		String sql = "insert into t_student (name,age,birthday) values (?,?,?)";// ? 占位符
		PreparedStatement stmt2 = conn.prepareStatement(sql);
		String name = "小虎";
		int age = 20;
		Date date = new Date(System.currentTimeMillis());
		
		stmt2.setObject(1, name);//设置参数
		stmt2.setObject(2, age); //也可以使用对应参数类型,stmt2.setInt(2, age);
		stmt2.setObject(3, date);
		//使用executeUpdate执行DML语句
		stmt2.executeUpdate();

DQL语句

  使用Statement执行DQL语句:

		Statement stmt1 = conn.createStatement();//获取Statement对象
		//拼接sql
		String sql = "select * from t_student r where r.id = 1"; 
		//使用executeQuery执行
		ResultSet rs = stmt1.executeQuery(sql);//范围结果为ResultSet类型,与集合的迭代器类似
		while(rs.next()){//通过get方法获取每一列的值
			System.out.println(rs.getString("name")+"--"+rs.getInt("age")+"--"+rs.getTimestamp("birthday"));
		}

  使用Statement执行DQL语句:

		String sql = "select * from t_student r where r.id = ?";// ? 占位符
		PreparedStatement stmt2 = conn.prepareStatement(sql);//获取PreparedStatement对象
		stmt2.setObject(1, 2);//设置参数
		//使用executeUpdate执行DML语句
		ResultSet rs = stmt2.executeQuery();
		while(rs.next()){
			System.out.println(rs.getString("name")+"--"+rs.getInt("age")+"--"+rs.getTimestamp("birthday"));
		}

批处理

  当需要一次性插入多条数据时,若条数特别多时,一行一行插入且一行行提交,那么效率就会显得相当的慢。这时我们可以使用批处理,取消自动提交,改为手动提交,并通过addBatch()方法将多条sql语句加在一起。实例:

		conn.setAutoCommit(false);  //取消自动提交,设为手动提交
		Statement stmt1 = conn.createStatement();//获取Statement对象
		String name = "小猪";
		int age = 18;
		Date date = new Date(System.currentTimeMillis());
		for(int i=0;i<20000;i++){
			//addBatch,将多条sql语句放在一起,待一起执行
			stmt1.addBatch("insert into t_student (name,age,birthday) "
					+ "values ('" + name + i + "'," + age + ",'"+ date +"')");
		}
		stmt1.executeBatch(); // 使用executeBatch方法,批量执行
		conn.commit();  //手动提交事务

操作CLOB与BLOB

  在数据库中,还有两个大对象类型,就是CLOB(文本大对象)与BLOB(二进制大对象),可以用来存储占用空间较大的数据,最大可达4G。

  操作CLOB读写实例:

		//写clob
		String sql = "insert into t_student (name,age,info) values (?,?,?)";
		PreparedStatement ps = conn.prepareStatement(sql);
		ps.setObject(1, "小猪");
		ps.setObject(2, 18);
		ps.setClob(3, new FileReader(new File("e:/test.txt")));//clob文本类型,与字符流对接
		ps.executeUpdate();
		//读clob
		String sql = "select * from t_student r where r.id = ? ";
		PreparedStatement ps = conn.prepareStatement(sql);
		ps.setObject(1, 20009);
		ResultSet rs = ps.executeQuery();
		while(rs.next()) {
			Clob c = rs.getClob("info");
			Reader r  = c.getCharacterStream();//通过getCharacterStream方法,得到字符输出流
			int len = 0;
			char[] flush = new char[1024];
			while((len=r.read(flush))!=-1){ //字符输出流的操作
				for(int i=0;i<len;i++) {
					System.out.print(flush[i]); //输出为字符
				}
			}
		}

  操作BLOB读写实例:

		//写blob
		String sql = "insert into t_student (name,age,headimage) values (?,?,?)";
		PreparedStatement ps = conn.prepareStatement(sql);
		ps.setObject(1, "小猪");
		ps.setObject(2, 18);
		ps.setBlob(3, new FileInputStream(new File("e:/a.jpg")));//blob二进制类型,与字节流对接
		ps.executeUpdate();
		//读blob
		String sql = "select * from t_student r where r.id = ? ";
		PreparedStatement ps = conn.prepareStatement(sql);
		ps.setObject(1, 20010);
		ResultSet rs = ps.executeQuery();
		while(rs.next()) {
			Blob b = rs.getBlob("headimage");
			InputStream is  = b.getBinaryStream();//通过getBinaryStream方法,得到字节输出流
			int len = 0;
			byte[] flush = new byte[1024];
			while((len= is.read(flush))!=-1){ //字节输出流的操作
				for(int i=0;i<len;i++) {
					System.out.print(flush[i]); //输出为字节
				}
			}
		}

调用存储过程

  通过prepareCall方法,获得Statement对象,则可以来调用存储过程。需要注意的是输出输出参数的设置与取值,实例:

		String call = "{call proc_test(?,?)};"; //调用存储过程语句,第一个参数为输入参数,第二个为输出参数
		
		CallableStatement proc = conn.prepareCall(call); //通过prepareCall方法,获得Statement对象
		proc.setString(1,"20020"); //给输入参数传值
		proc.registerOutParameter(2,Types.VARCHAR); //声明输出参数是什么类型的
		proc.execute(); //执行
		
		String res = proc.getString(2); //获得输出参数

第五步:释放资源

  同其他资源释放步骤一样,后使用的,先释放。实例:

try {
   //jdbc操作...省略
}catch(e){
   //异常捕获与处理
}finally{ //在finally中释放资源,后使用的,先释放。JDBC主要有以下三个资源需要释放
		try {
			if(rs!=null){ //rs  ResultSet 执行结果对象
				rs.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		try {
			if(ps!=null){    // ps Statement 执行语句对象
				ps.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		try {
			if(conn!=null){   //conn Connection 连接对象
				conn.close();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值