JDBC学习笔记!

JDBC:Java DataBase Connectivity

JDBC是sun公司制定的一套接口,目的是为了进行面向接口编程。因为每个数据库底层实现原理不一样,这就需要制定这样一套接口来连接各大数据库。
为什么面向接口编程:解耦合。降低程序的耦合度,提高程序的扩展力。

  • JDBC编程六步:

  • 第一步:注册驱动(告诉java程序,即将要连接哪个品牌的数据库)

DriverManager.registerDriver(Driver driver);
  • 第二步:获取连接(表示JVM的进程和数据库进程之间的通道打开,这属于进程之间的通信,重量级,使用完之后一定要关闭)
Connection conn = DriverManager.getConnection(String url,String user,String password);

url是网络资源定位符,由协议,ip地址,端口号,虚拟目录,文件名组成。

  • 第三步:获取数据库操作对象(用来专门执行Sql语句)
Statement stem = conn.createStatment()
  • 第四步:执行Sql语句(DQL,DML…)
String sql = "即将要执行的sql语句";
int count = stem.executeUpdate(String sql)//这条语句只能执行update,delete,insert语句,sql为要发送给数据库的sql语句
返回整数表示这条语句改变了数据库多少信息条数
  • 第五步:处理查询结果集(只有当第四步执行的是selecet语句的时候,才有这第五步查询结果集)
  • 第六步:释放资源(使用完资源之后一定要关闭资源。java和数据库属于进程之间的通信,开启之后一定要关闭)
    • 最后的释放资源一定要放在finally语句中,并且要分开try catch,目的是为了保证一定能执行

怎么有效记住这六步,首先,注册驱动,如果要与数据库产生关系首先要连接起来,然后要执行Sql语句的话,要先获取数据库对象,然后才能对数据库进行操作,然后就是执Sql语句,对结果集进行处理,最后释放资源,关闭通道。

import java.sql.*;

public static void main(String[] args){
	Connection conn = null;
	Statement stem = null;
	try{
		//注册驱动
		//DriverManager.registDriver(new com.mysql.jdbc.Driver());这种方法不常使用,有一种更好的方法就是使用类加载
		//Class.forName(String path);
		Class.forName("com.mysql.jdbc.Driver");
		//使用类加载可以直接执行类中的静态代码块
		
		//获取连接
		String url = "*****";
		String user = "******";
		String password = "*********";
		
		conn = DriverManager.getConnection(url,user,passwoer);
		
		//获取数据库操作对象
		stem = conn.createStatement();
		//执行sql语句
		String sql = "sql语句"int count = stem.executeUpdate(sql);
		System.out.println(count == 1? "数据库连接成功" : "数据库连接失败");
	}catch(SQLException e){
		e.printStackTrace();
	}finall{
		//释放资源
		if(stem != null){
			try(){
				stem.close();			
			}catch(SQLException e){
				e.printStackTrace();
			}
		}
		if(conn != null){
			try(){
				conn.close();
			}catch(SqlException e){
				e.printStackTrace();
			}
		}
	}
}

在实际开发中,我们将用户名及密码通常写在配置文件中,再通过资源绑定器(ResourceBundle来获取)

import java.sql.*;
import java.uti.*;

public static void main(String[] args){
	//将用户名,密码,ip,协议写在属性配置文件里,然后通过ResourceBundle获取用户名,密码
	Connection conn = null;
	Statement stem = null;
	ResultSet rs = null;//用来处理查询结果集
	ResourceBundle re = ResourceBundle.getBundle("jdbc");
	String user = re.getString("user");
	String password = re.getString("password");
	String url = re.getString("url");
	String driver = re.getString("driver");
	try{
		Class.forName(driver);
		conn = DriverManager.getConnection(url,user,passwoer);
		stem = conn.createStatement();
		String sql = "sql语句";
		int count = stem.executeUpdate(sql);//支持增删改语句
		rs = stem.executeQuery(sql);//获取指定的sql查询语句,返回单个ResultSet对象
		/*
		对查询结果集进行遍历
		rs.next()将当前光标移至下一行,如果下一行有数据返回true,没有返回false
		
		while(rs.next()){
		
			//通过指定列获取查询结果集中的内容
			String no = rs.getString(1);
			String nnum = rs.getString(2);
			String name = rs.getString(3);
			
			//这种方法更为健壮
			//get方法中的字符串是sql查询语句中的名字,
			//比如select sno as no from t_student get方法里面的字符串应该是no而不是sno
			
			String no = rs.getString("no");
			String num = rs.getString("num");
			String name = rs.getString("name");
			//并不是只有getString()一种方法,还有getInt(" "),getDouble("")等方法
		}
		*/
		System.out.println(count == 1? "成功" : "失败");
	}catch(SQLException e){
		e.printStackTrace();
	}finall{
		if(stem != null){
			try(){
				stem.close();			
			}catch(SQLException e){
				e.printStackTrace();
			}
		}
		if(conn != null){
			try(){
				conn.close();
			}catch(SqlException e){
				e.printStackTrace();
			}
		}
	}
}

使用JDBC的好处

  • 程序员如果要开发访问数据库的程序,只需要调用JDBC接口中的方法即可,不用关注类是如何实现的。
  • 使用一套java代码,就可以访问多个JDBC支持的数据库

使用JDBC过程中使用的类

DriverManager(Conection conn = DriverManager.getConnection();连接数据库)
Statement(Statement stem = conn.createStatement();创建数据库操作对象)
ResultSet rs = stem.executeQuery(String sql);执行选择语句用executeQuery()
int count = stem.executeUpdate(String sql);执行增删改语句

Sql注入

  • Sql注入的根本原因:用户输入的信息中含有Sql语句中的关键字(比如密码输入fdsa’ or ‘1’ = '1 在执行select语句后形成一条新的语句 select * from t_user where loginName = ‘fdsa’ and lobinPwd = ‘fdsa’ or ‘1’ = ‘1’),并且这些关键字参与了sql语句的编译过程,导致sql语句的原意被扭曲,进而导致sql注入。

  • 解决sql注入

    • 只要让让用户输入的信息不参与sql语句的编译,就不会产生sql注入的问题。
    • 将Statement数据库操作对象改为PreparedStatement
    • PreparedStatement接口继承了java.sql.Statement,是属于预编译的数据库操作对象,PreparedStatement的原理:预先对sql语句的框架进行编译,然后再给sql语句传值。

原语句:

Statement stem = null;
stem = conn.getConnection();
String sql = "select * from t_user where loginName = '"+loginName+"'and loginPwd = '"+loginPwd+"'"
stem.executeQuery(sql);

修改后:

PreparedStatement ps = null;
//?被称作占位符
String sql = "select * from t_user where loginName = ? and loginPwd = ?";
ps = conn.prepareStatement(sql);
//给占位符赋值,赋的是什么值就用set什么,jdbc的下标是从1开始的
ps.setrString(1,loginName);
ps.setString(2,loginPwd);
ps.execureQuery();
//然后接下来的executeQuery()就不用再传递sql语句了;

Statement与PreparedStatement的区别

  • Statement存在sql注入问题,PreparedStatement解决了sql注入的问题
  • Statement是编译一次执行一次,PreparedStatement是编译一次执行n次,效率要比Statement执行效率高
  • PreparedStatement会在编译的时候做类型的安全检查
  • 综上所述,PreparedStatement用的次数比较多,在需要sql注入(sql语句拼接)的时候用到Statement

事务

  • jdbc中的事务是自动提交的,即执行一句,提交一句,所以就需要使用到Connection类的setAutoCommit(boolean flag)方法,里面传一个boolean类型的值,当出现异常的时候,在catch中执行rollback()方法,当事务顺利执行完的时候执行commit()语句,表示提交事务。

JDBC工具类的封装

  • 由于在使用过程中有些代码频繁的使用,需要定义一个工具类类存放这些频繁使用的语句。(DBUtils)
public class Test{
	public static void main(String[] args){
		Connection conn = null;
		PreparedStatement ps =null;
		ResultSet rs = null;
		try{
			//获取数据库操作对象
			conn = DBUtil.getConnection();
			//sql语句
			String sql = "select * from t_user where name = ?";
			ps = conn.prepareStatement(sql);
			//模糊查询
			ps.setString(1,"_A%");
			rs = ps.executeQuery();
			while(rs.next()){
				System.out.println(rs.getString("name"));
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
		//		释放资源
			DBUtils.close(conn,stem,rs);
		}
	}
}



public class DBUtils{
	private DBUTils(){};
	static{
	//静态代码块在类加载的时候执行且执行一次
		try{
			Class.forName("com.mysql.jdbc.Driver");
		}catch(Execption e){
			e.printStackTrace();
		}
	}
	//由于在调用这个类的类中有try catch所以这里直接抛出Exception即可
	public static Connection getConnection() throws Exception{
		return DriverManager.getConnection(url,user,password);
	}
	public static void close(Connection conn, PreparedStatement ps, ResultSet rs){
		if(rs != null){
			try{
				rs.close();
			}catch(Exception e){
				e.printStackTrace();
			}
		}

		if(stem != null){
			try{
				stem.close();
			}catch(Exception e){
				e.printStackTrace();
			}
		}

		if(conn != null){
			try{
				conn.close();
			}catch(Exception e){
				e.printStackTrace();
			}
		}
	}
}

行级锁(行级锁)

  • 事务必须排队执行,事务锁住了,不允许并发
  • 乐观锁:支持事务并发,不需要排队,只不过需要一个版本号。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值