JDBC 技术

JDBC 技术

JDBC 简介

什么是 JDBC

  • JDBC(Java DataBase Connectivity)java数据库连接
  • 是JavaEE平台下的技术规范
  • 定义了在Java语言中连接数据库,执行SQL语句的标准
  • 可以为多种关系数据库提供统一访问

什么是数据库驱动程序

  • 数据库厂商对JDBC规范的具体实现
  • 不同数据产品需要依赖数据库驱动来完成对数据库的操作

程序操作数据库流程

在这里插入图片描述

JDBC3.0 标准中常用接口与类

Driver 接口

Driver 接口的作用是来定义数据库驱动对象应该具备的一些能力。比如与数据库建立连 接的方法的定义所有支持 java 语言连接的数据库都实现了该接口,实现该接口的类我们称 之为数据库驱动类。在程序中要连接数据库,必须先通过 JDK 的反射机制加载数据库驱动类,将其实例化。不同的数据库驱动类的类名有区别。

加载 MySql 驱动:Class.forName(“com.mysql.jdbc.Driver”);

加载 Oracle 驱动:Class.forName(“oracle.jdbc.driver.OracleDriver”);

DriverManager 类

DriverManager 通过实例化的数据库驱动对象,能够建立应用程序与数据库之间建立连 接。并返回 Connection 接口类型的数据库连接对象。

常用方法

getConnection(StringjdbcUrl,Stringuser,Stringpassword)

该方法通过访问数据库的 url、用户以及密码,返回对应的数据库的 Connection 对象

JDBC URL

与数据库连接时,用来连接到指定数据库标识符。在 URL 中包括了该数据库的类型、 地址、端口、库名称等信息。不同品牌数据库的连接 URL 不同。

Connection 接口
  • Connection 与数据库的连接(会话)对象。我们可以通过该对象执行 sql 语句并返回结
    果。

  • 连接 MySql 数据库:

    Connection conn = DriverManager.getConnection(“jdbc:mysql://host:port/database”, “user”, “password”);

  • 连接 Oracle 数据库:

    Connection conn = DriverManager.getConnection(“jdbc:oracle:thin:@host:port:database”, “user”,“password”);

  • 连接 SqlServer 数据库:

    Connection conn = DriverManager.getConnection(“jdbc:microsoft:sqlserver://host:port; DatabaseName=database”,“user”,“password”);

常用方法
  • createStatement():创建向数据库发送 sql 的 Statement 接口类型的对象。

  • preparedStatement(sql) :创建向数据库发送预编译 sql 的 PrepareSatement 接口类型的

  • prepareCall(sql):创建执行存储过程的 CallableStatement 接口类型的对象。 •

  • setAutoCommit(booleanautoCommit):设置事务是否自动提交。 •commit() :在链接上提交事务。 •

  • rollback() :在此链接上回滚事务。

Statement 接口

用于执行静态 SQL 语句并返回它所生成结果的对象。 由 createStatement 创建,用于发送简单的 SQL 语句(不支持动态绑定)。

常用方法
  • execute(String sql):执行参数中的 SQL,返回是否有结果集。
  • executeQuery(Stringsql):运行 select 语句,返回 ResultSet 结果集。
  • executeUpdate(Stringsql):运行 insert/update/delete 操作,返回更新的行数。
  • addBatch(Stringsql) :把多条 sql 语句放到一个批处理中。
  • executeBatch():向数据库发送一批 sql 语句执行。
PreparedStatement 接口

继承自 Statement 接口,由 preparedStatement 创建,用于发送含有一个或多个参数的 SQL 语句。PreparedStatement 对象比 Statement 对象的效率更高,并且可以防止 SQL 注入,所以 我们一般都使用 PreparedStatement。

常用方法
  • addBatch()把当前 sql 语句加入到一个批处理中。
  • execute() 执行当前 SQL,返回个 boolean 值
  • executeUpdate()运行 insert/update/delete 操作,返回更新的行数。
  • executeQuery() 执行当前的查询,返回一个结果集对象
  • setDate(intparameterIndex,Date x)向当前SQL语句中的指定位置绑定一个java.sql.Date
    值。
  • setDouble(int parameterIndex, double x)向当前 SQL 语句中的指定位置绑定一个 double
  • setFloat(intparameterIndex,floatx)向当前 SQL 语句中的指定位置绑定一个 float 值
  • setInt(intparameterIndex,intx)向当前 SQL 语句中的指定位置绑定一个 int 值
  • setString(intparameterIndex,Stringx)向当前 SQL 语句中的指定位置绑定一个 String 值
ResultSet 接口

ResultSet 提供检索不同类型字段的方法。

常用方法
  • getString(intindex)、getString(StringcolumnName) 获得在数据库里是 varchar、char 等类型的数据对象
  • getFloat(intindex)、getFloat(StringcolumnName) 获得在数据库里是 Float 类型的数据对象。
  • getDate(intindex)、getDate(StringcolumnName) 获得在数据库里是 Date 类型的数据。
  • getBoolean(intindex)、getBoolean(StringcolumnName) 获得在数据库里是 Boolean 类型的数据。
  • getObject(intindex)、getObject(StringcolumnName) 获取在数据库里任意类型的数据。
ResultSet 对结果集进行滚动的方法
  • next():移动到下一行。
  • Previous():移动到前一行。
  • absolute(introw):移动到指定行。
  • beforeFirst():移动 resultSet 的最前面。
  • afterLast() :移动到 resultSet 的最后面。
CallableStatement 接口

继承自 PreparedStatement 接口,由方法 prepareCall 创建,用于调用数据库的存储过程。

JDBC执行SQL语句过程

  1. 注册驱动

    Class.forName("com.mysql.jdbc.Driver");
    
  2. 创建连接

    conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjsxt"
    	+ "?useUnicode=true&character=utf-8", "root", "root");
    
  3. 执行SQL

    String sql = "INSERT INTO departments VALUES(DEFAULT, '" + department_name + "', " + location_id + ")";
    statement = conn.createStatement();
    int flag = statement.executeUpdate(sql);
    
  4. 关闭连接

    先关Statement,再关Connection

    if (null != statement) {
    	try {
    		statement.close();
    	} catch (SQLException e) {
    		// TODO Auto-generated catch block
    		e.printStackTrace();
    	}
    }
    
    if (null != conn) {
    	try {
    		conn.close();
    	} catch (SQLException e) {
    		// TODO Auto-generated catch block
    		e.printStackTrace();
    	}
    }
    

简单封装JDBC工具类

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * jdbc工具类
 * 	//获取Connection对象
	//关闭Statement
	//关闭Connection
 * @author ad
 *
 */
public class JdbcUtil {
	private static String driver = "com.mysql.jdbc.Driver";
	private static String jdbcUrl = "jdbc:mysql://localhost:3306/bjsxt"
			+ "?useUnicode=true&character=utf8";
	private static String username = "root";
	private static String password = "root";
	static {
		try {
			Class.forName(driver);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * 获取Connection
	 * @return
	 */
	public static Connection getConnection() {
		Connection conn = null;
		try {
			conn = DriverManager.getConnection(jdbcUrl, username, password);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return conn;
	}
	
	/**
	 * 关闭Statement
	 * @param State
	 */
	
	public static void closeStatement(Statement state) {
		if (null == state) {
			try {
				state.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 关闭Connection
	 * @param conn
	 */
	public static void closeConnection(Connection conn) {
		if (null == conn) {
			try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	//关闭资源
	public static void closeResource(Connection conn, Statement state) {
		closeStatement(state);
		closeConnection(conn);
	}

	
	public static void main(String[] args) {
		getConnection();
	}
}

使用properties文件优化JDBC工具类

1.将配置信息存放到properties文件中

driver = com.mysql.jdbc.Driver
jdbcUrl = jdbc:mysql://localhost:3306/bjsxt?useUnicode=true&character=utf8
username = root
password = root
  1. 读取properties文件

通过ResourceBundle来读取

ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
driver = bundle.getString("driver");
jdbcUrl = bundle.getString("jdbcUrl");
username = bundle.getString("username");
password = bundle.getString("password");
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;

/**
 * jdbc工具类
 * 	//获取Connection对象
	//关闭Statement
	//关闭Connection
 * @author ad
 *
 */
public class JdbcUtil {
	private static String driver;
	private static String jdbcUrl;
	private static String username;
	private static String password;
	static {
		//读取properties文件
		ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
		driver = bundle.getString("driver");
		jdbcUrl = bundle.getString("jdbcUrl");
		username = bundle.getString("username");
		password = bundle.getString("password");
		try {
			Class.forName(driver);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * 获取Connection
	 * @return
	 */
	public static Connection getConnection() {
		Connection conn = null;
		try {
			conn = DriverManager.getConnection(jdbcUrl, username, password);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return conn;
	}
	
	/**
	 * 关闭Statement
	 * @param State
	 */
	
	public static void closeStatement(Statement state) {
		if (null == state) {
			try {
				state.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 关闭Connection
	 * @param conn
	 */
	public static void closeConnection(Connection conn) {
		if (null == conn) {
			try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	//关闭资源
	public static void closeResource(Connection conn, Statement state) {
		closeStatement(state);
		closeConnection(conn);
	}
	
	public static void closeResource(Connection conn, Statement state, ResultSet reSet) {
		closeStatement(state);
		closeConnection(conn);
		closeResultSet(reSet);
	}
	
	public static void closeResultSet(ResultSet reSet) {
		if (null == reSet) {
			try {
				reSet.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

查询

使用Statement对象查询数据

步骤与Update大致相同,查询多了操作返回的结果集ResultSet

//查询
	public void selectDepartmentsById(int departments_id) {
		Connection conn = null;
		Statement statement = null;
		ResultSet resultSet = null;
		try {
			conn = JdbcUtil.getConnection();
			String sql = "SELECT * FROM departments WHERE departments_id = " + 		departments_id;
			statement = conn.createStatement();
			//执行SQL
			resultSet = statement.executeQuery(sql);
			while (resultSet.next()) {
				System.out.println(resultSet.getInt("departments_id") + ":"
						+ resultSet.getString("department_name") + ":" 
						+ resultSet.getInt("location_id"));
			}

		} catch (Exception e) {
			
			e.printStackTrace();
		}	finally {
			JdbcUtil.closeResource(conn, statement, resultSet);
		}
	}

ResultSet

注意 ResultSet 中封装的并不是我们查询到的所有的结果集,而是返回了查询到的结果集的数据库游标。通过 ResultSet 中的 next()方法操作游标的位置获取结果集。

ResultSet逻辑分页

/**
	 * <p>currentPage 当前页数, pageRows 每页条数</p>
	 * @param currentPage 
	 * @param pageRows
	 */
	public void selectDepartmentsPage(int currentPage, int pageRows) {
		Connection conn = null;
		Statement statement = null;
		ResultSet resultSet = null;
		try {
			conn = JdbcUtil.getConnection();
			String sql = "SELECT * FROM departments";
			statement = conn.createStatement();
			//执行SQL
			resultSet = statement.executeQuery(sql);
			//开始位置与结束位置
			int begin = (currentPage - 1) * pageRows;
			int end = currentPage * pageRows;
			//当前位置的计数器
			int currentNum = 0;
			while (resultSet.next()) {
				//控制获取结果集的数据量
				if (currentNum >= begin && currentNum < end) {
					System.out.println(resultSet.getInt("departments_id") + ":"
							+ resultSet.getString("department_name") + ":" 
							+ resultSet.getInt("location_id"));
					//结束操作
					if (currentNum == end - 1) {
						break;
					}
				}
				currentNum++;
			}

		} catch (Exception e) {
			
			e.printStackTrace();
		} finally {
			JdbcUtil.closeResource(conn, statement, resultSet);
		}
	}

SQL注入问题

什么是SQL注入

所谓 SQL 注入,就是通过把含有 SQL 语句片段的参数插入到需要执行的 SQL 语句中, 最终达到欺骗数据库服务器执行恶意操作的 SQL 命令。

/**
 * 模拟SQL注入
 * @author ad
 *
 */
public class SQLInject {
	//查询
	public void selectDepartmentsById(String department_name, int location_id) {
		Connection conn = null;
		Statement statement = null;
		ResultSet resultSet = null;
		try {
			conn = JdbcUtil.getConnection();
			String sql = "SELECT * FROM departments WHERE department_name = '" + department_name + "' AND "
					+ "location_id = " + location_id;
			statement = conn.createStatement();
			//执行SQL
			resultSet = statement.executeQuery(sql);
			while (resultSet.next()) {
				System.out.println(resultSet.getInt("departments_id") + ":"
						+ resultSet.getString("department_name") + ":" 
						+ resultSet.getInt("location_id"));
			}

		} catch (Exception e) {
			
			e.printStackTrace();
		} finally {
			JdbcUtil.closeResource(conn, statement, resultSet);
		}
	}
	public static void main(String[] args) {
		SQLInject s = new SQLInject();
		s.selectDepartmentsById("研发部 ' or 1 = 1 -- ", 8);
	}
}

PreparedStatement 对象的使用

PreparedStatement 特点:

  • PreparedStatement 接口继承 Statement 接口
  • PreparedStatement 效率高于 Statement
  • PreparedStatement 支持动态绑定参数
  • PreparedStatement 具备 SQL 语句预编译能力
  • 使用 PreparedStatement 可防止出现 SQL 注入问

PreparedStatement 使用示例

	//使用PreparedStatement 向Departments表添加一条数据
	public void insertDepartments(String department_name, int location_id) {
		Connection conn = null;
		PreparedStatement ps = null;
		
		try {
			conn = JdbcUtil.getConnection();
			String sql = "INSERT INTO departments VALUES(DEFAULT, ?, ?)";
			ps = conn.prepareStatement(sql);
			ps.setString(1, department_name);
			ps.setInt(2, location_id);
			//执行SQL
			int flag = ps.executeUpdate();
			System.out.println("flag = " + flag);
		} catch (Exception e) {
			
			e.printStackTrace();
		}	finally {
			JdbcUtil.closeResource(conn, ps);
		}
	}

什么是预编译

SQL 语句的执行步骤
  • 语法和语义解析
  • 优化 sql 语句,制定执行计划
  • 执行并返回结果

但是很多情况,我们的一条 sql 语句可能会反复执行,或者每次执行的时候只有个别的 值不同(比如 select 的 where 子句值不同,update 的 set 子句值不同,insert 的 values 值不同)。 如果每次都需要经过上面的词法语义解析、语句优化、制定执行计划等,则效率就明显不行 了。

所谓预编译语句就是将这类语句中的值用占位符替代,可以视为将 sql 语句模板化或者 说参数化

预编译语句的优势在于:一次编译、多次运行,省去了解析优化等过程;此外预编译语 句能防止 sql 注入

解析过程

**硬解析 **

在不开启缓存执行计划的情况下,每次 SQL 的处理都要经过:语法和语义的解析,优 化器处理 SQL,生成执行计划。整个过程我们称之为硬解析。

**软解析 **

如果开启了缓存执行计划,数据库在处理 sql 时会先查询缓存中是否含有与当前 SQL 语句相同的执行计划,如果有则直接执行该计划。

预编译方式

开始数据库的日志

show VARIABLES like ‘%general_log%’

set GLOBAL general_log = on

set GLOBAL log_output=‘table’

依赖数据库驱动完成预编译

如果我们没有开启数据库服务端编译,那么默认的是使用数据库驱动完成 SQL 的预编 译处理。

依赖数据库服务器完成预编译

我们可以通过修改连接数据库的 URL 信息,添加 useServerPrepStmts=true 信息开启服 务端预编译。

使用PreparedStatement 对象完成数据的更新

	public void udateDempartements(int departments_id, String department_name, int location_id) {
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			conn = JdbcUtil.getConnection();
			String sql = "UPDATE departments SET department_name = ?, location_id = ? WHERE departments_id = ?";
			ps = conn.prepareStatement(sql);
			ps.setString(1, department_name);
			ps.setInt(2, location_id);
			ps.setInt(3, departments_id);
			//执行SQL
			int flag = ps.executeUpdate();
			System.out.println("flag = " + flag);
		} catch (Exception e) {
			
			e.printStackTrace();
		}	finally {
			JdbcUtil.closeResource(conn, ps);
		}
	}

使用PreparedStatement 对象完成单条结果查询

	public Departments selectDepartmentsById(int departmentId) {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		Departments dept = null;
		try {
			conn = JdbcUtil.getConnection();
			String sql = "SELECT * FROM departments WHERE departments_id = ?";
			ps = conn.prepareStatement(sql);
			
			ps.setInt(1, departmentId);
			rs = ps.executeQuery();
			while (rs.next()) {
				dept = new Departments();
				dept.setDepartmentId(rs.getInt("departments_id")) ;
				dept.setDepartmentName(rs.getString("department_name"));
				dept.setLocationId(rs.getInt("location_id"));
			}
		} catch (Exception e) {
			// TODO: handle exception
		} finally {
			JdbcUtil.closeResource(conn, ps, rs);
		}
		return dept;
	}

使用PreparedStatement 对象完成多条结果查询

使用容器接收结果集

	/**
	 * 多结果查询
	 * @param departmentName
	 * @return
	 */
	public List<Departments> selectDepartmentsByLikeName(String departmentName) {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		Departments dept = null;
		List<Departments> list = new ArrayList<Departments>();
		try {
			conn = JdbcUtil.getConnection();	
			String sql = "SELECT * FROM departments WHERE department_name like ?";
			ps = conn.prepareStatement(sql);	
			ps.setString(1, "%" + departmentName + "%");
			rs = ps.executeQuery();
			while (rs.next()) {	
				dept = new Departments();
				dept.setDepartmentId(rs.getInt("departments_id")) ;
				dept.setDepartmentName(rs.getString("department_name"));
				dept.setLocationId(rs.getInt("location_id"));
				list.add(dept);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtil.closeResource(conn, ps, rs);
		}
		return list;
	}

使用PreparedStatement批处理

批处理:在与数据库的一次连接中,批量的执行条 SQL 语句。

	/**
	 * 批量添加
	 * @param list
	 */
	public void addBatch(List<Departments> list) {
		Connection conn = null;
		PreparedStatement ps = null;
		
		try {
			conn = JdbcUtil.getConnection();
			String sql = "INSERT INTO departments VALUES(DEFAULT, ?, ?)";
			ps = conn.prepareStatement(sql);
			for (Departments departments : list) {
				ps.setString(1, departments.getDepartmentName());
				ps.setInt(2, departments.getLocationId());
				//添加批处理
				ps.addBatch();
			}
			//执行SQL
			int[] flag = ps.executeBatch();
			for (int i : flag) {
				System.out.println(i);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}	finally {
			JdbcUtil.closeResource(conn, ps);
		}
	}
	

JDBC中的事务处理

在 JDBC 操作中数据库事务默认为自动提交。如果事务需要修改为手动提交,那么我们 需要使用 Connection 对象中的 setAutoCommit 方法来关闭事务自动提交。然后通过 Connection 对象中的 commit 方法与 rollback 方法进行事务的提交与回滚。

在exexute之前设置都有效

//关闭自动提交
conn.setAutoCommit(false);
//手动提交
conn.commit(); 

//在异常中使用
conn.rollback();

所有的DML操作建议都使用手动提交。

多条DML操作只要出现异常,所有的操作都会回滚。

	/**
	 * 删除操作
	 * 手动提交事务
	 * @param departmentId
	 */
	public void deleteDepartmentById(int departmentId) {
		Connection conn = null;
		PreparedStatement ps = null;
		
		try {
			conn = JdbcUtil.getConnection();
			//关闭自动提交
			conn.setAutoCommit(false);
			String sql = "DELETE FROM departments WHERE departments_id = ?";
			ps = conn.prepareStatement(sql);
			ps.setInt(1, departmentId);
			System.out.println(ps.executeUpdate());
			//手动提交
			conn.commit();
		} catch (Exception e) {
			//出现异常,回滚
			try {
				conn.rollback();
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			e.printStackTrace();
		} finally {
			JdbcUtil.closeResource(conn, ps);
		}
	}

JDBC进阶

动态查询

根据用户给定的条件,来决定执行什么样的查询。

不给定条件时查询表中所有的数据

	/**
	 * 动态查询
	 * @param sqlDept
	 * @return
	 */
	public List<Departments> selectDepartmentByProperty(Departments sqlDept) {
		List<Departments> list = new ArrayList<Departments>();
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		Departments dept = null;
		try {
			conn = JdbcUtil.getConnection();
			String sql = genSQL(sqlDept);
			ps = conn.prepareStatement(sql);
			rs = ps.executeQuery();
			while (rs.next()) {
				dept = new Departments();
				dept.setDepartmentId(rs.getInt("departments_id"));
				dept.setDepartmentName(rs.getString("department_name"));
				dept.setLocationId(rs.getInt("location_id"));
				list.add(dept);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtil.closeResource(conn, ps, rs);
		}
		return list;
	}
	
	/**
	 * 拼接SQL
	 * @param sqlDept
	 * @return
	 */
	private String genSQL(Departments dept) {
		StringBuilder sb = new StringBuilder("SELECT * FROM departments WHERE 1 = 1 ");
		if (null != dept) {
			if (0 < dept.getDepartmentId()) {
				sb.append("and departments_id = ").append(dept.getDepartmentId());
			}
			if (null != dept.getDepartmentName()) {
				sb.append("and department_name = '").append(dept.getDepartmentName() + "'");
			}
			if (0 < dept.getLocationId()) {
				sb.append("and location_id = ").append(dept.getLocationId());
			}
		}
		return sb.toString();
	}

应用程序分层

应用程序通过创建不同的包来实现项目的分层,将项目中的代码根据功能做具体划分, 并存放在不同的包下。

分层优点
  1. 分层结构将应用系统划分为若干层,每一层只解决问题的一部分,通过各层的协作 提供整体解决方案。大的问题被分解为一系列相对独立的子问题,局部化在每一层中,这样 就有效的降低了单个问题的规模和复杂度,实现了复杂系统的第一步也是最为关键的一步分 解。
  2. 分层结构具有良好的可扩展性,为应用系统的演化增长提供了一个灵活的支持,具 有良好的可扩展性。增加新的功能时,无须对现有的代码做修改,业务逻辑可以得到最大限 度的重用。
  3. 分层架构易于维护。在对系统进行分解后,不同的功能被封装在不同的层中,层与 层之间的耦合显著降低。因此在修改某个层的代码时,只要不涉及层与层之间的接口,就不 会对其他层造成严重影响。
三层结构

三层结构就是将整个业务应用划分为:界面层(User Interface layer)、业务逻辑层 (BusinessLogicLayer)、数据访问层(Dataaccesslayer)。区分层次的目的即为了“高内 聚低耦合”的思想。在软件体系架构设计中,分层式结构是最常见,也是最重要的一种结构。

项目分层

在这里插入图片描述

commos包:存放工具类

dao.impl:数据访问层,存放操作数据库的代码

pojo:模型层,存放实体对象

service:业务层,负责处理相应的业务

在分层结构中实现业务

持久层

持久层的方法要原子化,提高复用率。

接口

public interface DepartmentsDao {
	public List<Departments> selectDeptByName(String deptName);
	public void insertDept(Departments dept);
}

实现类

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import com.trf.commos.JdbcUtil;
import com.trf.dao.DepartmentsDao;
import com.trf.pojo.Departments;

public class DepartmentsDaoImpl implements DepartmentsDao {

	@Override
	public List<Departments> selectDeptByName(String deptName) {
		List<Departments> list = new ArrayList<Departments>();
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		Departments d = null;
		try {
			conn = JdbcUtil.getConnection();
			ps = conn.prepareStatement("SELECT * FROM departments WHERE department_name = ?");
			ps.setString(1, deptName);
			rs = ps.executeQuery();
			while (rs.next()) {
				d = new Departments();
				d.setDepartmentId(rs.getInt("departments_id"));
				d.setDepartmentName(rs.getString("department_name"));
				d.setLocationId(rs.getInt("location_id"));
				list.add(d);
			}
		} catch (Exception e) {
			e.printStackTrace();

		} finally {
			JdbcUtil.closeResource(conn, ps);
		}
		
		return list;
	}

	@Override
	public void insertDept(Departments dept) {
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			conn = JdbcUtil.getConnection();
			conn.setAutoCommit(false);
			ps = conn.prepareStatement("INSERT INTO departments VALUES(DEFAULT, ?, ?)");
			ps.setString(1, dept.getDepartmentName());
			ps.setInt(2, dept.getLocationId());
			ps.executeUpdate();
			conn.commit();
		} catch (Exception e) {
			e.printStackTrace();
			JdbcUtil.rollback(conn);
		} finally {
			JdbcUtil.closeResource(conn, ps);
		}
	}

}

业务层

接口

import java.util.List;

import com.trf.pojo.Departments;

public interface DepartmentsService {
	public void addDepartments(Departments dept);
	public List<Departments> selectDepartmentsByName(String deptName);
}

实现类

import java.util.List;

import com.trf.dao.DepartmentsDao;
import com.trf.dao.impl.DepartmentsDaoImpl;
import com.trf.pojo.Departments;
import com.trf.service.DepartmentsService;

public class DepartmentsServiceImpl implements DepartmentsService {

	@Override
	public void addDepartments(Departments dept) {
		DepartmentsDao deptDao = new DepartmentsDaoImpl();
		deptDao.insertDept(dept);
	}

	@Override
	public List<Departments> selectDepartmentsByName(String deptName) {
		DepartmentsDao deptDao = new DepartmentsDaoImpl();
		return deptDao.selectDeptByName(deptName);
	}

}

测试
import java.util.List;
import com.trf.pojo.Departments;
import com.trf.service.DepartmentsService;
import com.trf.service.impl.DepartmentsServiceImpl;

public class Test {
	public static void main(String[] args) {
		Departments dept = new Departments();
		dept.setDepartmentName("闻达共享单车洗菜部");
		dept.setLocationId(5);
		DepartmentsService ds = new DepartmentsServiceImpl();
		//ds.addDepartments(dept);
		List<Departments> list = ds.selectDepartmentsByName("闻达共享单车洗菜部");
		System.out.println(list);
	}
}

封装通用的BaseDao

BaseDao

/**
 * 通用DML操作接口
 * @author ad
 *
 */
public interface BaseDao {
	/**
	 * 
	 * @param sql 需要执行的DML语句
	 * @param param 参数
	 * @return
	 */
	public int executeUpdate(String sql, Object ... param);
}

BaseDaoImpl

import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import com.trf.commos.JdbcUtil;
import com.trf.dao.BaseDao;

public class BaseDaoImpl implements BaseDao{

	/**
	 * 封装通用的DML操作
	 * @author ad
	 *
	 */
	public int executeUpdate(String sql, Object... param) {
		Connection conn = null;
		PreparedStatement ps = null;
		int rows = 0;
		try {
			conn = JdbcUtil.getConnection();
			conn.setAutoCommit(false);
			ps = conn.prepareStatement(sql);
			//得到参数的个数
			ParameterMetaData pmd = ps.getParameterMetaData();
			//绑定参数
			for (int i = 1; i <= pmd.getParameterCount(); i++) {
				ps.setObject(i, param[i-1]);
			}
			rows = ps.executeUpdate();
			conn.commit();
		} catch (Exception e) {
			e.printStackTrace();
			JdbcUtil.rollback(conn);
		} finally {
			JdbcUtil.closeResource(conn, ps);
		}
		return rows;
	}

}

Dao层接口

import java.util.List;

import com.trf.pojo.Departments;

/**
 * 持久层的方法要原子化,提高复用率
 * @author ad
 *
 */
public interface DepartmentsDao extends BaseDao{

	/**
	 * 更新
	 * @param dept
	 * @return
	 */
	public int updateDept(Departments dept);
	/**
	 * 删除
	 * @param dept
	 * @return
	 */
	public int deleteDeptById(Departments dept);
}

Dao层实现类

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import com.trf.commos.JdbcUtil;
import com.trf.dao.BaseDao;
import com.trf.dao.DepartmentsDao;
import com.trf.pojo.Departments;

public class DepartmentsDaoImpl extends BaseDaoImpl implements DepartmentsDao {

	/**
	 * 更新部门信息
	 */
	public int updateDept(Departments dept) {
		String sql = "UPDATE departments set department_name = ?, location_id = ? WHERE departments_id = ?";
		return this.executeUpdate(sql, dept.getDepartmentName(), dept.getLocationId(), dept.getDepartmentId());
	}

	/**
	 * 删除部门信息
	 */
	public int deleteDeptById(Departments dept) {
		String sql = "DELETE FROM departments WHERE departments_id = ?";
		return this.executeUpdate(sql, dept.getDepartmentId());
	}


}

Service层接口


import java.util.List;

import com.trf.pojo.Departments;

public interface DepartmentsService {
	/**
	 * 更新
	 * @param dept
	 * @return
	 */
	public int modifyDepartments(Departments dept);
	/**
	 * 删除
	 * @param dept
	 * @return
	 */
	public int deleteDepartmentsById(Departments dept);
}

Service层实现类

import com.trf.dao.DepartmentsDao;
import com.trf.dao.impl.DepartmentsDaoImpl;
import com.trf.pojo.Departments;
import com.trf.service.DepartmentsService;

public class DepartmentsServiceImpl implements DepartmentsService {

	@Override
	public int modifyDepartments(Departments dept) {
		DepartmentsDao deptDao = new DepartmentsDaoImpl();
		return deptDao.updateDept(dept);
	}

	@Override
	public int deleteDepartmentsById(Departments dept) {
		DepartmentsDao deptDao = new DepartmentsDaoImpl();
		return deptDao.deleteDeptById(dept);
	}

}

封装查询操作

BaseDao接口

/**
 * 通用操作接口
 * @author ad
 *
 */
public interface BaseDao {
	
	/**
	 * 通用查询方法
	 * @param <T>
	 * @param sql 需要执行的查询语句
	 * @param clazz 返回集合的泛型
	 * @param param 查询的参数
	 * @return
	 */
	public <T>List<T> find(String sql, Class<T> clazz, Object ... param);
}

BaseDao实现类

public class BaseDaoImpl implements BaseDao{

	/**
	 * <p>实现通用查询方法</p>
	 * <p><T> List<T>:泛型方法</p>
	 * <p>通用查询方法要求实体模型成员变量名与数据库字段名相对应</p>
	 */
	@Override
	public <T> List<T> find(String sql, Class<T> clazz, Object... param) {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		List<T> list = new ArrayList<T>();
		try {
			conn = JdbcUtil.getConnection();
			ps = conn.prepareStatement(sql);
			//得到参数的个数
			ParameterMetaData pmd = ps.getParameterMetaData();
			for (int i = 0; i < pmd.getParameterCount(); i++) {
				ps.setObject(i + 1, param[i]);
			}
			//处理结果集
			rs = ps.executeQuery();
			//获取结果集信息
			ResultSetMetaData rsmd = rs.getMetaData();
			while (rs.next()) {
				//使用反射完成ORM
				T bean = clazz.newInstance();
				for (int i = 0; i < rsmd.getColumnCount(); i++) {
					//获得列名
					String columnName = rsmd.getColumnName(i + 1);
					//获得值
					Object value = rs.getObject(columnName);
					//使用BeanUtil工具类将值存放到对象中
					BeanUtils.setProperty(bean, columnName, value);
				}
				list.add(bean);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtil.closeResource(conn, ps);
		}
		return list;
	}

}

Dao接口

/**
 * 持久层的方法要原子化,提高复用率
 * @author ad
 *
 */
public interface DepartmentsDao extends BaseDao{
	public int deleteDeptById(Departments dept);
	
	/**
	 * 部门名Like查询
	 * @param deptName
	 * @return
	 */
	public List<Dept> selectDeptByLikeName(String deptName);
}

Dao实现类

public class DepartmentsDaoImpl extends BaseDaoImpl implements DepartmentsDao {
	@Override
	public List<Dept> selectDeptByLikeName(String deptName) {
		String sql = "SELECT * FROM departments WHERE department_Name LIKE ?";
		return this.find(sql, Dept.class, "%" + deptName + "%");
	}


}

Service接口

public interface DepartmentsService {
	/**
	 * 部门名Like查询
	 * @param deptName
	 * @return
	 */
	public List<Dept> findDeptByLikeName(String deptName);
}

Service接口实现类

public class DepartmentsServiceImpl implements DepartmentsService {
	@Override
	public List<Dept> findDeptByLikeName(String deptName) {
		DepartmentsDao deptDao = new DepartmentsDaoImpl();
		return deptDao.selectDeptByLikeName(deptName);
	}

}

JDBC驱动加载原理

创建对象的方式

在这里插入图片描述

创建对象时三个重要的步骤
  • 通过类加载器加载 class
  • 初始化所有静态部分
  • 为新生对象分配内存
MySQL驱动类的实例化过程
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }
  1. 在使用Class.forName(“com.mysql.jdbc.Driver”)注册数据库驱动时,完成了Driver类的加载 ,和Driver类的静态初始化。

  2. Driver类在静态初始化时通过反射实例化自身,并将对象交给DriverManager类进行管理;

  3. 所以才可以通过DriverManager.getConnection()获取数据库连接。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值