IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> JAVA——JDBC进阶 -> 正文阅读

[大数据]JAVA——JDBC进阶

目录

1.??????使用PreparedStatement

2.封装JDBC

3.JDBC分页查询

4.事务的控制

5.工厂设计模式(解耦合)


1.??????使用PreparedStatement

(1)好处:避免SQL注入(SQL注入是一种注入攻击,可以执行恶意SQL语句。)

(2)例子

①数据库表

drop table if exists user;
create table user (
	name varchar(10),
	password varchar(15)
);
insert into user(name, password) values
('tom1', '123456'),
('tom2', '123456'),
('tom3', '123456'),
('tom4', '123456'),
('tom5', '123456');

②Java代码?

package com.sqlinsert.test;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
 
/**
 * SQL注入是一种注入攻击,可以执行恶意SQL语句。
 */
public class SqlInsert {
	/**
	 * @param name
	 * @param password
	 * TODO 判断用户是否存在
	 * @return 布尔值
	 */
	public static boolean login(String name, String password) {//使用处理对象Statement
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		boolean flag = false;//默认用户不存在
		String sql = "select * from user where name = " + name + " and password = '" + password + "';";
		try {
			//注册驱动
			Class.forName("com.mysql.jdbc.Driver");
			
			//获取数据库连接
			conn = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai",
					"root", "123456");
			
			//获取执行对象
			stmt = conn.createStatement();
			
			//执行sql语句
			rs = stmt.executeQuery(sql);
			if (rs.next()) {
				flag = true;//该用户存在
			}
		} catch (Exception 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();
			}
		}
		return flag;
	}
	
	/**
	 * @param name
	 * @param password
	 * TODO 判断该用户是否存在
	 * @return 布尔值
	 */
	public static boolean loginStronger(String name, String password) {//使用预处理对象PreparedStatement
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		boolean flag = false;//默认用户不存在
		//使用占位符? 避免SQL注入
		String sql = "select * from user where name = ? and password = ?;";
		try {
			//注册驱动
			Class.forName("com.mysql.jdbc.Driver");
			
			//获取数据库连接
			conn = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai",
					"root", "123456");
			
			//获取执行对象
			stmt = conn.prepareStatement(sql);
			//为两个占位符赋值
			stmt.setString(1, name);
			stmt.setString(2, password);
			
			//执行sql语句
			rs = stmt.executeQuery();
			if (rs.next()) {
				flag = true;//该用户存在
			}
		} catch (Exception 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();
			}
		}
		return flag;
	}
 
	public static void main(String[] args) {
		/*此时sql语句为:select * from user where name = null and password = 'null' or 1 = '1';
		 * 无论账号和密码是否正确,都会提示的”该用户存在!“
		 */
		boolean flag = login("null", "null' or 1 = '1");
		if (flag) {
			System.out.println("该用户存在!");
		} else {
			System.out.println("该用户不存在!");
		}
		
		/* 此时,可以正常判断用户是否存在了 */
		boolean flag2 = loginStronger("null", "null' or 1 = '1");
		if (flag2) {
			System.out.println("该用户存在!");
		} else {
			System.out.println("该用户不存在!");
		}
	}
}

③执行结果

该用户存在!
该用户不存在!

2.封装JDBC

①封装JDBC工具类

Ⅰ.在src下创建文件“jdbc_dev.properties”,内容如下

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
user=root
password=123456

?Ⅱ.创建包“com.XXX.util”,并包里面创建DBUtils类,代码如下

package com.lqh.util;
 
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
 
/**
 * @author lqh JDBC工具类
 */
public class DBUtils {
	private static String driver = null;
	private static String url = null;
	private static String user = null;
	private static String password = null;
	
	
	//静态代码块
	static{
		//使用类加载器加载属性文件
		//把文件一定放在src路径下
		InputStream is = DBUtils.class.getClassLoader().getResourceAsStream("jdbc_dev.properties");
		Properties props = new Properties();
		try {
			props.load(is);
			driver = props.getProperty("driver");
			url = props.getProperty("url");
			user = props.getProperty("user");
			password = props.getProperty("password");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/** 获取数据库连接对象
	 * @return 连接对象
	 */
	public static Connection getConnection(){
		Connection conn = null;
		try {
			Class.forName(driver);
			conn = DriverManager.getConnection(url, user, password);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return conn;
	}
	
	/** 释放资源
	 * @param conn
	 * @param stmt
	 * @param rs
	 */
	public static void close(Connection conn, Statement stmt, ResultSet rs){
		try {
			if(rs != null){
				rs.close();
			}
			if(stmt != null){
				stmt.close();
			}
			if(conn != null){
				conn.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

?②根据数据库中的表创建实体类

Ⅰ.数据库中有表:

DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp`  (
  `id` int NOT NULL,
  `name` varchar(15) NOT NULL,
  `hiredate` date NOT NULL,
  `sal` decimal(10, 2) NOT NULL,
  PRIMARY KEY (`id`)
);
INSERT INTO `emp` VALUES (1, 'jesson', '1988-12-02', 4521.50);
INSERT INTO `emp` VALUES (2, 'amy', '2012-12-12', 3589.50);
INSERT INTO `emp` VALUES (3, 'mary', '2022-02-10', 2545.20);
INSERT INTO `emp` VALUES (4, 'ken', '2020-02-10', 3526.20);
INSERT INTO `emp` VALUES (5, 'henry', '2012-02-10', 4553.20);
INSERT INTO `emp` VALUES (6, 'chen', '2015-05-13', 6541.50);
INSERT INTO `emp` VALUES (7, 'li', '1998-01-09', 6545.50);
INSERT INTO `emp` VALUES (8, 'ha', '2022-01-01', 3500.50);

Ⅱ.创建包“com.XXX.entity”,创建Emp类

package com.lqh.entity;
 
import java.util.Date;
 
/** 雇员,实体类
 * @author lqh
 */
public class Emp {
	/** 雇员ID */
	private Integer id;
	
	/** 雇员姓名 */
	private String name;
	
	/** 雇员入职日期 */
	private Date hiredate;
	
	/** 雇员薪水 */
	private Double sal;
 
	//提供属性访问器getter和setter
	public Integer getId() {
		return id;
	}
 
	public void setId(Integer id) {
		this.id = id;
	}
 
	public String getName() {
		return name;
	}
 
	public void setName(String name) {
		this.name = name;
	}
 
	public Date getHiredate() {
		return hiredate;
	}
 
	public void setHiredate(Date hiredate) {
		this.hiredate = hiredate;
	}
 
	public Double getSal() {
		return sal;
	}
 
	public void setSal(Double sal) {
		this.sal = sal;
	}
 
	/** 提供有参构造函数 */
	public Emp(Integer id, String name, Date hiredate, Double sal) {
		super();
		this.id = id;
		this.name = name;
		this.hiredate = hiredate;
		this.sal = sal;
	}
	
	/** 提供无参构造函数 */
	public Emp(){
	}
 
	/** 重写toString方法,方便查看对象里面的所有信息 */
	@Override
	public String toString() {
		return "Emp [id=" + id + ", name=" + name + ", hiredate=" + hiredate + ", sal=" + sal + "]";
	}
}

③创建“com.XXX.dao”包,创建Emp对应的dao层,即EmpDao类

package com.lqh.dao;
 
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
 
import com.lqh.entity.Emp;
import com.lqh.util.DBUtils;
 
/** 数据访问层
 * @author lqh
 */
public class EmpDao {
	//把sql语句从方法中剥离出来定义成常量
	private static final String INSERT_EMP = "insert into emp(id, name, hiredate, sal) values(?, ?, ?, ?);";
	private static final String DELETE_EMP = "delete from emp where id = ?;";
	private static final String QUERY_ALLEMP = "select id, name, hiredate, sal from emp;";
 
	/** 添加雇员
	 * @param emp
	 * @return 添加结果
	 */
	public boolean insertEmp(Emp emp){
		boolean result = false;//用于存放添加的结果
		Connection conn = null;
		PreparedStatement pstmt = null;
		try {
			conn = DBUtils.getConnection();//从工具类获取连接对象
			pstmt = conn.prepareStatement(INSERT_EMP);
			pstmt.setInt(1, emp.getId());
			pstmt.setString(2, emp.getName());
			pstmt.setDate(3, new Date(emp.getHiredate().getTime()));//sql包和util包的date之间的转换
			pstmt.setDouble(4, emp.getSal());
			int num = pstmt.executeUpdate();
			result = (num > 0)?true: false;
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			DBUtils.close(conn, pstmt, null);//释放资源
		}
		return result;
	}
	
	/** 通过雇员id删除雇员信息
	 * @param id
	 * @return 删除结果
	 */
	public boolean deleteEmpById(int id){
		boolean result = false;//用于存放删除的结果
		Connection conn = null;
		PreparedStatement pstmt = null;
		try {
			conn = DBUtils.getConnection();//从工具类获取连接对象
			pstmt = conn.prepareStatement(DELETE_EMP);
			pstmt.setInt(1, id);
			int num = pstmt.executeUpdate();
			result = (num > 0)?true: false;
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			DBUtils.close(conn, pstmt, null);//释放资源
		}
		return result;
	}
	
	/** 通过雇员id修改雇员信息
	 * @param emp
	 * @return 修改结果
	 */
	public boolean updateEmpById(Emp emp){
		boolean result = false;//用于存放修改的结果
		Connection conn = null;
		PreparedStatement pstmt = null;
		StringBuffer sql = new StringBuffer("update emp set");//存放sql语句
		try {
			conn = DBUtils.getConnection();//从工具类获取连接对象
			if(emp.getName() != null && !"".equals(emp.getName())){//雇员姓名不为空
				sql.append(" name = '" + emp.getName() + "',");//拼接sql语句
			}
			if(emp.getHiredate() != null && !"".equals(emp.getHiredate())){//入职日期不为空
				sql.append(" hiredate = '" + emp.getHiredate() + "',");//拼接sql语句
			}
			if(emp.getSal() != null && !"".equals(emp.getSal())){//薪水不为空
				sql.append(" sal = " + emp.getSal() + ",");
			}
			sql.delete(sql.length() - 1, sql.length());//移除sql语句中的“,”
			sql.append(" where id = " + emp.getId());//给sql添加限制条件
			
			pstmt = conn.prepareStatement(sql.toString());
			int num = pstmt.executeUpdate();
			result = (num > 0)?true: false;
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			DBUtils.close(conn, pstmt, null);//释放资源
		}
		return result;
	}
	
	/** 查询所有雇员信息
	 * @return 所有雇员信息
	 */
	public List<Emp> queryAllEmp(){
		List<Emp> emps = new ArrayList<>();
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		conn = DBUtils.getConnection();
		try {
			pstmt = conn.prepareStatement(QUERY_ALLEMP);
			rs = pstmt.executeQuery();
			while(rs.next()){
				Emp emp = new Emp();
				emp.setId(rs.getInt("id"));//这里,rs.getInt("id")等价于:rs.getInt(1),但不建议写后者
				emp.setName(rs.getString("name"));
				emp.setHiredate(rs.getDate("hiredate"));
				emp.setSal(rs.getDouble("sal"));
				emps.add(emp);//往集合添加查询到的对象
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			DBUtils.close(conn, pstmt, rs);
		}
		return emps;
	}
}

3.JDBC分页查询

package com.lqh.dao;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
 
import com.lqh.entity.Emp;
import com.lqh.util.DBUtils;
 
/** 数据访问层
 * @author lqh
 */
public class EmpDao {
	private static final String QUERY_EMP_BY_PAGEANDNUMBER = "select id, name, hiredate, sal from emp limit ?, ?;";
 
	/** 雇员信息每number个为一页,显示第page页
	 * @param page
	 * @param number
	 * @return 第page页雇员信息
	 */
	public List<Emp> queryEmpByPageAndNumber(int page, int number){
		List<Emp> emps = new ArrayList<>();
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			conn = DBUtils.getConnection();
			pstmt = conn.prepareStatement(QUERY_EMP_BY_PAGEANDNUMBER);
			pstmt.setInt(1, (page - 1) * number);//从下标为:(page - 1) * number开始查询总数据数为number
			pstmt.setInt(2, number);
			rs = pstmt.executeQuery();
			while(rs.next()){
				Emp emp = new Emp();
				emp.setId(rs.getInt("id"));
				emp.setName(rs.getString("name"));
				emp.setHiredate(rs.getDate("hiredate"));
				emp.setSal(rs.getDouble("sal"));
				emps.add(emp);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			DBUtils.close(conn, pstmt, rs);
		}
		return emps;
	}
}

4.事务的控制

package com.lqh.dao;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
 
import com.lqh.util.DBUtils;
 
/** 数据访问层
 * @author lqh
 */
public class EmpDao {
 
	private static final String UPDATE_SAL = "update emp set sal = sal + ? where id = ?;";
 
	/** 两个雇员之间的转账(from:转账人id,to:收钱方id,sal:转账金额)
	 * @param from
	 * @param to
	 * @param sal
	 * @return 转账结果
	 */
	public boolean updateSal(int from, int to, double sal){
		boolean isFlag = false;
		Connection conn = null;
		PreparedStatement pstmt = null;
		try {
			conn = DBUtils.getConnection();
			
			/** 设置数据库为手动提交 */
			conn.setAutoCommit(false);
			
			pstmt = conn.prepareStatement(UPDATE_SAL);
			
			//转账人:
			pstmt.setDouble(1, -sal);
			pstmt.setInt(2, from);
			int num1 = pstmt.executeUpdate();
			
			//这时遇到算数异常,第一条sql语句能成功执行,第二条不行
			//所以需要在处理异常catch里面,回滚事务
			//System.out.println(1 / 0);
			
			//收钱方:
			pstmt.setDouble(1, sal);
			pstmt.setInt(2, to);
			int num2 = pstmt.executeUpdate();
			
			if(num1 > 0 && num2 > 0){//只有送钱和收钱两个行为完成了才提交
				conn.commit();//提交事务
			}
		} catch (Exception e) {
			try {
				//回滚事务,防止因为出现异常,只执行了一条sql语句,另一个未执行
				conn.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
		} finally{
			DBUtils.close(conn, pstmt, null);
		}
		return isFlag;
	}
}

5.工厂设计模式(解耦合)

(1)创建EmpDaoIfac接口

点击“Refactor”,选中"Extract Interface",输入接口名“EmpDaoIfac”,勾选所有EmpDao里创建的方法

?(2) 创建工厂类DaoFactory

package com.lqh.dao;
 
/** dao工厂
 * @author lqh
 */
public class DaoFactory {
	public static EmpDao getEmpDao(){
		return new EmpDao();
	}
}

(3)创建包“com.XXX.service”,创建业务层EmpService类

package com.lqh.service;
 
import java.util.List;
 
import com.lqh.dao.DaoFactory;
import com.lqh.dao.EmpDaoIfac;
import com.lqh.entity.Emp;
 
/** 业务层,调用dao层方法
 * @author lqh
 */
public class EmpService {
	private EmpDaoIfac empDao = DaoFactory.getEmpDao();//从dao工厂里面获取EmpDao实例化对象,可以解耦合
	
	/** 雇佣新员工
	 * @param emp
	 * @return 雇佣结果
	 */
	public boolean hire(Emp emp){
		return empDao.insertEmp(emp);
	}
	
	/** 裁员
	 * @param id
	 * @return 裁员结果
	 */
	public boolean fire(int id){
		return empDao.deleteEmpById(id);
	}
	
	/** 修改雇员信息
	 * @param emp
	 * @return 修改结果
	 */
	public boolean changeEmpInfo(Emp emp){
		return empDao.updateEmpById(emp);
	}
	
	/** 显示所有员工信息
	 * @return 所有员工信息
	 */
	public List<Emp> showAllEmp(){
		return empDao.queryAllEmp();
	}
	
	/** 转账
	 * @param from
	 * @param to
	 * @param sal
	 * @return 转账结果
	 */
	public boolean transfer(int from, int to, double sal){
		return empDao.updateSal(from, to, sal);
	}
}

(4)创建EmpServiceIfac接口

(5)创建工厂类ServiceFactory

package com.lqh.service;
 
/** service工厂
 * @author lqh
 */
public class ServiceFactory {
	public static EmpService getEmpService(){
		return new EmpService();
	}
}

?

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-03-11 22:17:06  更:2022-03-11 22:20:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:46:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码