JDBC学习3:使用preparedstatement实现CRUD操作

一.对数据库操作的简介

1.操作数据库的接口

①statement(静态sql语句)

②preparedstatement(SQL语句预编译)

③callablestatement(执行SQL的存储过程)

⑤CRUD操作

  • create retrieve update delete

2.statement出现的问题

①拼接字符串麻烦

需要显示的拼接字符串

②SQL注入问题:没有检查语句

  • 实际语句:where user = ‘1’ OR ‘AND password=’ = 1 OR ‘1’='1’此语句必然返回true
  • 拼接语句:where user = ’ “+user+” ’ AND password =’ " +password+ " ’
  • 输入语句:user:1’ OR password:= 1 OR ‘1’='1
  • 此时产生歧义,会导致无论如何都能够登录成功

二.使用preparedstatement来实现增删改查

1.增删改(无返回值)

①数据库连接获得connection

  • 获取配置文件信息
  • 注册驱动类的对象
  • 获取connection

②利用connection获取preparedstatement实例

  • 获取preparedstatement实例‘
  • 定义预编译sql语句
  • 填充sql语句
  • 执行实例

③关闭资源

  • preparedstatement
  • connection

④代码举例(向customers添加一条记录)

//向customers添加一条记录
	@Test
	public void testInsert() throws Exception{
		//1.获取配置文件信息(加载配置文件+读取配置文件)
		InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
		Properties pros = new Properties();
		pros.load(is);
					
		String user = pros.getProperty("user");
		String password = pros.getProperty("password");
		String url = pros.getProperty("url");
		String driverClass = pros.getProperty("driverClass");
					
		//2.注册驱动类的对象(加载运行时类和注册运行时类对象)
		Class.forName(driverClass);
					
		//3.获取connection
		Connection conn = DriverManager.getConnection(url, user, password);
		//System.out.println(conn);
		
		//4.预编译sql语句,返回preparestatement实例
		String sql = "insert into customers(name,email,birth) values(?,?,?)";//?占位符
		PreparedStatement ps = conn.prepareStatement(sql);
		
		//5.填充占位符
		ps.setString(1, "哪吒");
		ps.setString(2, "enzha@qq.com");
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		java.util.Date date = sdf.parse("1000-01-01");
		ps.setDate(3, new Date(date.getTime()));
		
		//6.执行操作
		ps.execute();
		
		//7.资源关闭
		ps.close();
		conn.close();
		
	}

⑤代码举例(适用于任何表的增删改)

+通用获取连接和关闭连接操作

//获取数据库资源
	public static Connection getConnection() throws Exception{
		//获取配置文件信息(加载配置文件+读取配置文件)
		//1.获取配置文件信息(加载配置文件+读取配置文件)
		InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
		Properties pros = new Properties();
		pros.load(is);
					
		String user = pros.getProperty("user");
		String password = pros.getProperty("password");
		String url = pros.getProperty("url");
		String driverClass = pros.getProperty("driverClass");
					
		//2.注册驱动类的对象(加载运行时类和注册运行时类对象)
		Class.forName(driverClass);
					
		//3.获取connection
		Connection conn = DriverManager.getConnection(url, user, password);
		//System.out.println(conn);
		return conn;		
	}
	//关闭数据库资源
	public static void closeResource(Connection conn,Statement ps){
		try{
			if(ps != null)
				ps.close();
		}catch(SQLException e){
			e.printStackTrace();
		}
		try{
			if(conn != null)
				ps.close();
		}catch(SQLException e){
			e.printStackTrace();
		}
	}
  • 通用更新操作
```sql
//通用的更新操作
	public static void update(String sql,Object ...args) throws Exception{//sql占位符个数与可变形参长度一直
		//1.获取数据库的链接
		Connection conn = JDBCUtils.getConnection();
		//2.预编译sql语句返回preparedstatement实例(已经知道要干什么事儿)
		PreparedStatement ps = conn.prepareStatement(sql);
		//3.填充sql占位符
		for(int i = 0;i<args.length;i++){
			ps.setObject(i+1, args[i]);
		}
		//4.执行
		ps.execute();
		//5.关闭资源
		JDBCUtils.closeResource(conn, ps);
	}

public void testCommon() throws Exception{
	String sql ="delete from customers where id = ?";
	JDBCUtils.update(sql, 3);
	
	//注意表名如果是关键字加上着重号
}

2.查询(有返回值)

①数据库连接获得connection

  • 获取配置文件信息
  • 注册驱动类的对象
  • 获取connection

②利用connection获取preparedstatement实例

  • 获取preparedstatement实例‘
  • 定义预编译sql语句
  • 填充sql语句
  • 执行实例并返回结果集

③利用结果集初始化对应对象

  • 获取结果集的元数据(包含列名,返回的列值信息)
  • 结果集获得列值,元数据获得列名
  • 通过反射利用列名设置对象的列值
  • 注意:此时拿到的是列名而不是属性名,如果列名和属性名不同,需要在select语句中显示改别名为属性名。使用第二个获取别名
    getcolunmname()//获取列名
    getcolumnlabel()//获取别名

④关闭资源

  • preparedstatement
  • connection
  • resultSet

⑤代码举例

  • 得到确定的数据(得到一条查询结果)
@Test
	public void testQuery1(){
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet resultSet = null;
		try {
			conn = JDBCUtils.getConnection();
			String sql = "select id,name,email,birth from customers where id = ?";
			ps = conn.prepareStatement(sql);
			ps.setObject(1, 1);
			
			//增删改执行ps.execute无返回,此时需要有返回结果集,调用ps.executeQuery();返回结果集
			resultSet = ps.executeQuery();
			//处理结果集
			if(resultSet.next()){//next作用判断结果集下一条是否发有数据,有数据返回true指针下移,没有数据返回false指针不下移
				//获取当前数据的各个字段值
				int id = resultSet.getInt(1);
				String name = resultSet.getString(2);
				String email = resultSet.getString(3);
				Date birth = resultSet.getDate(4);
				//low
				//System.out.println("id =" + id);
				//也不好
				//Object[] data = new Object[](id,name,email,birth);
				//数据封装为对象
				Customer customer = new Customer(id,name,email,birth);
				System.out.println(customer);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//关闭资源
		JDBCUtils.closeResource(conn, ps,resultSet);
	}	
  • 不确定的查询语句返回(返回一条结果)
//对customer表的通用查询操作
	public static Customer customerEquiry(String sql,Object ...args) throws Exception{
		//1.获取数据库的链接
		Connection conn = JDBCUtils.getConnection();
		//2.预编译sql语句返回preparedstatement实例(已经知道要干什么事儿)
		PreparedStatement ps = conn.prepareStatement(sql);
		//3.填充sql占位符
		for(int i = 0;i<args.length;i++){
			ps.setObject(i+1, args[i]);
		}
		ResultSet resultSet = ps.executeQuery();
		//获取结果集的元数据,通过元数据获取结果集的列数
		ResultSetMetaData rsmd = resultSet.getMetaData();
		
		int column = rsmd.getColumnCount();
		//4.返回结果集
		if(resultSet.next()){//next作用判断结果集下一条是否发有数据,有数据返回true指针下移,没有数据返回false指针不下移
			Customer cust = new Customer();
			//处理结果集一行数据的每一个列
			for(int i = 0;i < column;i++){
				//获取列值
				Object columnvalue = resultSet.getObject(i+1);
				
				//获取结果集中的每个列的列名
				String columnName = rsmd.getColumnName(i+1);
				
				//给cust对象指定的某个属性columnName赋值为columnvalue,通过反射
				Field field = Customer.class.getDeclaredField(columnName);
				field.setAccessible(true);
				field.set(cust, columnvalue);
			}
			return cust;
		}
		JDBCUtils.closeResource(conn, ps, resultSet);
		return null;
	}
}
  • 不确定的表以及多条返回结果
//实现针对不同表的查询操作(返回表中的一条记录)
	//T对应的运行时类的名称
	public static <T> T  getInstance(Class<T> clazz,String sql,Object ...args) throws Exception{
		//1.获取数据库的链接
		Connection conn = JDBCUtils.getConnection();
		//2.预编译sql语句返回preparedstatement实例(已经知道要干什么事儿)
		PreparedStatement ps = conn.prepareStatement(sql);
		//3.填充sql占位符
		for(int i = 0;i<args.length;i++){
			ps.setObject(i+1, args[i]);
		}
		ResultSet resultSet = ps.executeQuery();
		//获取结果集的元数据,通过元数据获取结果集的列数
		ResultSetMetaData rsmd = resultSet.getMetaData();
		
		int column = rsmd.getColumnCount();
		//4.返回结果集
		if(resultSet.next()){//next作用判断结果集下一条是否发有数据,有数据返回true指针下移,没有数据返回false指针不下移
			T t = clazz.newInstance();
			//处理结果集一行数据的每一个列
			for(int i = 0;i < column;i++){
				//获取列值
				Object columnvalue = resultSet.getObject(i+1);
				
				//获取结果集中的每个列的列名
				String columnName = rsmd.getColumnName(i+1);
				
				//Class clazz1 =  T.class;为什么下面不能写T.class
				
				//给t对象指定的某个属性columnName赋值为columnvalue,通过反射
				Field field = clazz.getDeclaredField(columnName);
				field.setAccessible(true);
				field.set(t, columnvalue);
			}
			return t;
		}
		JDBCUtils.closeResource(conn, ps, resultSet);
		return null;
	}
	//针对不同的表返回多条数据
	public static <T> List<T> getForList(Class<T> clazz,String sql,Object ...args) throws Exception{
		//1.获取数据库的链接
		Connection conn = JDBCUtils.getConnection();
		//2.预编译sql语句返回preparedstatement实例(已经知道要干什么事儿)
		PreparedStatement ps = conn.prepareStatement(sql);
		//3.填充sql占位符
		for(int i = 0;i<args.length;i++){
			ps.setObject(i+1, args[i]);
		}
		ResultSet resultSet = ps.executeQuery();
		//获取结果集的元数据,通过元数据获取结果集的列数
		ResultSetMetaData rsmd = resultSet.getMetaData();				
		int column = rsmd.getColumnCount();
		//集合对象
		ArrayList<T> list = new ArrayList<T>();
		while(resultSet.next()){
			T t = clazz.newInstance();
			//处理结果集一行数据的每一个列;给t对象指定的属性赋值
			for(int i = 0;i < column;i++){
				//获取列值
				Object columnvalue = resultSet.getObject(i+1);
						
				//获取结果集中的每个列的列名
				String columnName = rsmd.getColumnName(i+1);
						
				//Class clazz1 =  T.class;为什么下面不能写T.class
						
				//给t对象指定的某个属性columnName赋值为columnvalue,通过反射
				Field field = clazz.getDeclaredField(columnName);
				field.setAccessible(true);
				field.set(t, columnvalue);
				}
			list.add(t);
		}
		JDBCUtils.closeResource(conn, ps, resultSet);
		return list;
	}

3.preparedstatement特性(用占位符)

①解决sql注入问题

  • preparedstatement预编译sql语句(传入参数前已经确定了关系),然后挖两个坑传入参数
  • statement直接用完整sql语句执行

②preparedstatement可以操作Blob类型数据,而statement做不到

③preparedstatement实现高效的批量操作

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值