JDBC基础

JDBC数据库连接技术

为什么使用JDBC?

​ 因为在Java使用的数据都是瞬时数据,在内存中运行完后会被销毁,数据库可以持久化存储数据,但两者之间是独立的个体,需要将两个独立个体连接起来,这时候 就需要使用JDBC数据库连接技术

JDBC概念

​ JDBC(Java DataBase Connectivity) 是Java提供的一套用于连接访问数据库执行SQL的标准规范(接口),接口的实现由对应的数据库厂商提供

JDBC执行流程

在这里插入图片描述

​ 历史: 以前在JDBC连接技术中,数据库连接的实现由程序员编写OJDBC技术,但是这种技术在切换数据库后需要重新编写实现

​ 现在: 为了节约开发和时间从成本,数据库的实现由数据库厂商统一提供-----JDBC技术

​ 实现步骤:

​ 1.加载驱动 Class.forName(path)

​ 2.通过DriverManager.getConntion(url,name,password)获取连接,并返回连接对象

​ 3.通过Connection去接收连接对象

​ 4.通过conn对象创建出Statement执行接口对象

​ 5.statement对象执行sql,进行操作

​ 6.如果是更新方法返回受影响行数(int),执行查询方法返回Resultset结果集对象

​ 7.获取数据

​ 8.关闭资源

JDBC中核心的接口和类

​ 1,DriverManager类:这是一个类

​ 1,负责管理驱动,注册驱动

​ 2,通过该类中的静态方法,getConnection()方法就可以得到一个该数据库的连接对象

​ 2,Connection接口

​ 1,负责跟数据库建立了一条连接

​ 2,通过该接口的实现类对象,还可以得到一个Statement对象

3,Statement接口

​ 1,相当于小货车,负责执行sql语句,并且返回结果

​ 2,通过调用该接口中的查询的方法,就返回了一个ResultSet结果集对象

4,ResultSet接口

​ 1,当查询的时候,把数据库中的数据封装在结果集当中,输回给java

​ 2,遍历该结果集中的数据,通过一个next(),指针,每次读取一行记录

​ 连接数据库

ublic class ConnectionDemo {

	public static void main(String[] args) {
		Connection conn = null;
		try {
			//1.加载驱动,可能找不到这个名称的类,所以报出找不到类的异常
			Class.forName("com.mysql.jdbc.Driver");
			//2.通过DriverManager建立连接,可能出现url错误连接不上报出异常
			/*
			 * jdbc: 主协议----使用什么技术
			 * mysql: 自协议---连接的数据库
			 * :// 连接协议
			 * localhost 连接IP  表示本机与127.0.0.1相同
			 * 3306 数据库指定端口号
			 * test 连接的数据库
			 * ? 表示拼接属性
			 * characterEncoding   编码字符集设置  utf-8
			 * root 用户名和密码   如果没有密码不填写第三个参数
			 */
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?characterEncoding=utf-8","root","root");
			System.out.println(conn);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

使用statement对象添加数据

public class SaveGrade {

	public static void main(String[] args) {
		Connection conn = null;
		Statement st = null;
		Grade grade = new Grade(5, "研究生", "没事就研究研究");
		try {
			//1.加载驱动
			Class.forName("com.mysql.jdbc.Driver");
			//2.建立连接
			conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8", "root", "root");
			//3.获取到statement执行对象
			st = conn.createStatement();
			//4.准备需要执行的SQL语句
			//statement采用的是拼接式sql执行,字符型数据需要主动加上单引号
			String sql = "insert into grade values("+grade.getGid()+",'"+grade.getGname()+"','"+grade.getGdesc()+"')";
			//5.执行sql并返回受影响行数,用于执行更新(增删改)调用executeUpdate(sql)方法
			int row = st.executeUpdate(sql);
			System.out.println("插入行数:"+row);
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				st.close();
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

使用statement修改对象

public class UpdateGrade {
	//修改数据库数据
	public static void main(String[] args) {
		Connection conn = null;
		Statement st = null;
		Grade g = new Grade(3, "大三", "即将面临就业,需要努力的时候");
		try {
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?characterEncoding=utf-8", "root", "root");
			st = conn.createStatement();
			String sql = "update grade set gname='"+g.getGname()+"',gdesc='"+g.getGdesc()+"' where gid="+g.getGid();
			int row = st.executeUpdate(sql);
			System.out.println("修改成功行数:"+row);
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				st.close();
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

使用statement删除对象

public class DeleteGrade {
	//修改数据库数据
	public static void main(String[] args) {
		Connection conn = null;
		Statement st = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?characterEncoding=utf-8", "root", "root");
			st = conn.createStatement();
			String sql = "delete from grade where gid=5";
			int row = st.executeUpdate(sql);
			System.out.println("删除成功行数:"+row);
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				st.close();
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

使用statement查询表,并返回ResultSet结果集

在这里插入图片描述

public class QueryGrade {
	//使用statement对象查询数据库,并返回结果集对象
	public static void main(String[] args) {
		Connection conn = null;
		Statement st = null;
		ResultSet rs = null;
		try {
			//1.加载驱动
			Class.forName("com.mysql.jdbc.Driver");
			//2.建立连接
			conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8", "root", "root");
			st = conn.createStatement();
			//准备查询语句,因为数据库查询结果会使用对象接收,一般查询全列
			String sql = "select * from grade";
			//使用st对象的,executeQuery(sql),并返回数据存储到ResultSet结果集中
			rs = st.executeQuery(sql);
			//遍历结果集内容
			// 结果集中有两个方法   next()判断结果集中是否有下一行数据    如果有使用getXXX()获取指定类型的值
			while(rs.next()) {
				System.out.println("年级编号为:"+rs.getInt("gid")+", 名称为:"+rs.getString(2)+", 描述:"+rs.getString(3));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				rs.close();
				st.close();
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

使用Statement对象以拼接的方式做登录查询

​ 但是在登录过程中,因为SQL的拼接,造成sql结构错误,导致查询出错这种错误叫做SQL注入

public class LoginStatement {
	//SQL注入
	public static void main(String[] args) {
		Connection conn = null;
		Statement st = null;
		ResultSet rs = null;
		try {
			conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8", "root", "root");
			st = conn.createStatement();
			String name="admin",password="1234567 or 1=1";
			//通过设置密码,与拼接sql的形式组合,在密码中注入了一个 or 1=1的SQL片段,这就是sql注入
			String sql = "select * from user where name='"+name+"' and password="+password;
			//执行查询方法,并返回rs结果集
			rs = st.executeQuery(sql);
			while(rs.next()) {
				System.out.println("用户ID为:"+rs.getInt(1)+", 用户名:"+rs.getString(2)+", 密码为:"+rs.getString(3));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				rs.close();
				st.close();
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}
PreparedStatement接口

​ preparedstatement接口是Statement的子接口,因为Statement容易被SQL注入,使用preparedstatement预编译SQL的方式解决Statement中SQL注入的问题

PreparedStatement添加数据

​ 1.先准备sql

​ 2.再获取Preparedstatement对象,并预编译SQL句(在创建对象的同时,先将SQL读入到pst对象中,所有需要填值的地方使用?占位符表示)

​ 3.对占位符赋值,位置从1开始,如果没有占位符就不需要赋值

public class SaveGrade {

	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement pst = null;
		Grade grade = new Grade(5, "研究生", "没事就研究研究");
		try {
			//1.加载驱动
			Class.forName("com.mysql.jdbc.Driver");
			//2.建立连接
			conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8", "root", "root");
			//3.准备sql,?表示占位符,指定位置等待赋值
			String sql = "insert into grade values(?,?,?)";
			//4.获取到pst执行对象,预编译sql语句,保证sql不出问题
			pst = conn.prepareStatement(sql);
			//5.为占位符赋值,占位符的位置从1开始
			pst.setInt(1, grade.getGid());
			pst.setString(2, grade.getGname());
			pst.setString(3, grade.getGdesc());
			//6.执行sql并返回受影响行数,用于执行更新(增删改)调用executeUpdate()方法
			//注意: 前面已经 预编译SQL了,这个位置只需要执行
			int row = pst.executeUpdate();
			System.out.println("插入行数:"+row);
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				pst.close();
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

使用PreparedStatement接口解决查询sql注入

public class LoginPst {

	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement pst = null;
		ResultSet rs = null;
		try {
			conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8", "root", "root");
			String name="admin",password="1234567 or 1=1";
			//通过设置密码,与拼接sql的形式组合,在密码中注入了一个 or 1=1的SQL片段,这就是sql注入
			String sql = "select * from user where name=? and password=?";
			pst = conn.prepareStatement(sql);
			pst.setString(1, name);
			pst.setString(2, password);
			//执行查询方法,并返回rs结果集
			rs = pst.executeQuery();
			while(rs.next()) {
				System.out.println("用户ID为:"+rs.getInt(1)+", 用户名:"+rs.getString(2)+", 密码为:"+rs.getString(3));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				rs.close();
				pst.close();
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

优化jdbc代码,把重复的代码抽取出来单独放在方法当中,把变的使用变量表示,从而可以实现简化代码的作用

/**
 * JDBC操作的工具类 对jdbc的代码进行了优化,简化了代码 对于重复的代码就使用方法进行重用,从而减少了代码量
 * 
 *
 */
public class JDBCTools2 {
	private static  String driver;
	private static  String url;
	private static  String user;
	private static  String password;
	private static Connection con;

	// 静态代码块,当初始化当前类时才会执行,并且只会执行一次
	static {
		try {
			try {
				//实例化一个Properties对象,该对象就可以读取properties配置文件
				Properties p = new Properties();
				//需要把jdbc.properties配置文件构造成一个流对象
				//InputStream is = new FileInputStream("resources\\jdbc.properties");
				InputStream is = JDBCTools2.class.getClassLoader().getResourceAsStream("jdbc.properties");
				//把配置文件加载到Properties对象当中
				p.load(is);
				
				//就可以根据键获取到值
				driver = p.getProperty("jdbc.driverclass");
				url = p.getProperty("jdbc.url");
				user = p.getProperty("jdbc.user");
				password = p.getProperty("jdbc.password");
				System.out.println("driver:"+driver);
				System.out.println("url:"+url);
				System.out.println("user:"+user);
				System.out.println("password:"+password);
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			// 加载驱动
			Class.forName(driver);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 专门获得数据库连接的方法
	 * 
	 * @return 数据库连接对象
	 */
	public static Connection getCon() {
		//相当于变成了一个单例的了
		try {
			// 为空或者连接已经关闭了
			if (con == null || con.isClosed()) {
				con = DriverManager.getConnection(url, user, password);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return con;
	}
	
	
	/**
	 * 关闭数据库连接的方法
	 * @param con
	 * @param ps
	 * @param rs
	 */
	public static void closeAll(Connection con,Statement ps,ResultSet rs ) {
		try {
			// 关闭数据库连接, 释放数据库资源
			if (con != null) {
				con.close();
			}
			if (ps != null) {
				ps.close();
			}
			if (rs != null) {
				rs.close();
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 增删改的通用方法
	 * 可变类型参数 Object... parametes  Object[] parametes
	 * @param sql
	 * @param parametes
	 * @return
	 */
	public static int executeUpdate(String sql,Object... parametes ) {
		//得到一个数据库连接对象
		Connection con = getCon();
		PreparedStatement ps=null;
		try {
			 ps = con.prepareStatement(sql);
			 //传递参数
			 //非空判断
			 if(parametes!=null&&parametes.length>0) {
				 for(int i=0;i<parametes.length;i++) {
					 ps.setObject(i+1, parametes[i]);
				 }
			 }
			 int iret = ps.executeUpdate();
			 return iret;
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			//关闭数据库连接资源
			closeAll(con,ps,null);
		}
		return 0;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喜欢木木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值