Java 反射封装增删改查通用方法

博主声明:

转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。

本文首发于此   博主:威威喵  |  博客主页:https://blog.csdn.net/smile_running

  • JDBC简介

      JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。(官方语言描述,看看就好。)

      JDBC,它就像驱动一样,数据库比如:mysql、oracle、db2、sqlSever等,不同的产商肯定实现的方式都不一样,那就要求程序员得每一个数据库的操作都得学会,只有这样才能跟上需求的改变。所以,JDBC,它就站出来了。它为每个产商提供相同的接口,不管数据库底层如何实现。相当于在数据库与应用程序中间加了一层,这就是 JDBC。那么,加了这一层,程序员们就可以通过 JDBC 固定 API 来操作各种不同数据库了,相当机智。

  • JDBC 连接 MySQL 数据库

代码如下:

public class JdbcUtils {

	public static Connection getConnection() throws Exception {
		/**
		 * 步骤:
		 *  1. 声明  driver、jdbcUrl、user、password 四个变量
		 *  2. 新建 jdbc.properties 配置文件,使其在不改源码情况下,变更数据库
		 *  3. 获取 jdbc.properties 文件参数,利用Java反射和输入流方式获取
		 *  4. Class.forName(driver);加载驱动
		 *  5. 获取连接实例
		 */
		String driver = null;
		String jdbcUrl = null;
		String user = null;
		String password = null;

		InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
		Properties properties = new Properties();
		properties.load(inputStream);
		driver = properties.getProperty("driver");
		jdbcUrl = properties.getProperty("jdbcUrl");
		user = properties.getProperty("user");
		password = properties.getProperty("password");
		Class.forName(driver);
		Connection conn = (Connection) DriverManager.getConnection(jdbcUrl, user, password);
		return conn;
	}

	public static void release(Statement statement, Connection conn, ResultSet result) {
		try {
			if (statement != null) {
				statement.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		try {
			if (conn != null) {
				conn.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		try {
			if (result != null) {
				result.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

    这里我写了一个Jdbc获取连接的工具类,只要调用 getConnection() 方法就可以连接成功了。注意一点:MySQL 数据库连接参数为如下(也就是上面代码中注释部分 jdbc.properties 文件内容),否则将连不上,MySQL 端口和用户名都是默认的。

Java 反射封装增删改查通用方法_第1张图片

上图的 person 代表的是你的数据库名称。

  • JDBC 增、删、改、查

    数据库为上文 user 表(图在上面)

  • 增、删、改方法

public class JdbcTest {

	/**
	 * 提供: 增 、删、改3个功能的通用方法
	 * 
	 * @param sql 
	 * @param args sql 中占位符的值,可以用多个逗号隔开
	 */
	public void update(String sql, Object... args) throws Exception {
		Connection connection = null;
		PreparedStatement preparedStatement = null;

		try {
			connection = JdbcUtils.getConnection();
			System.out.println(sql);
			preparedStatement = connection.prepareStatement(sql);
			
			for (int i = 0; i < args.length; i++) {
				preparedStatement.setObject(i + 1, args[i]);
			}
			preparedStatement.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtils.release(preparedStatement, connection, null);
		}
	}

	@Test
	public void insert() throws Exception {
		String sql = "INSERT INTO user(user_name,sex,user_role,password,id_card,register_time)"
				+ " VALUES(?,?,?,?,?,?)";
		
		update(sql,"小红","女","VIP用户","xh","654...","2019-01-25 14:02:03");
	}

	@Test
	public void delete() throws Exception {
		// 删除 user 表中 user_name 为小红的信息
		String sql = "DELETE FROM user WHERE user_name=?";
		update(sql,"小红");
	}

	@Test
	public void modify() throws Exception {
		// user 表中 user_name 为小红 的用户,将其  user_role 改为 普通用户
		String sql = "UPDATE user set user_role=? WHERE user_name=?";
		update(sql,"普通用户","小红");
	}
}
  • 通用查询方法封装

    利用面向对象编程的思想,我们新建了一个 User 类,此类变量为 user 表对应的列名,代码如下:

package com.xww;

public class User {

	public String userName;
	public String password;
	public String registerTime;
	public String sex;
	public String userRole;
	public String idCard;

	public User(String userName, String password, String registerTime, 
			String sex, String userRole, String idCard) {
		super();
		this.userName = userName;
		this.sex = sex;
		this.userRole = userRole;
		this.password = password;
		this.idCard = idCard;
		this.registerTime = registerTime;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public String getUserRole() {
		return userRole;
	}

	public void setUserRole(String userRole) {
		this.userRole = userRole;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getIdCard() {
		return idCard;
	}

	public void setIdCard(String idCard) {
		this.idCard = idCard;
	}

	public String getRegisterTime() {
		return registerTime;
	}

	public void setRegisterTime(String registerTime) {
		this.registerTime = registerTime;
	}

	@Override
	public String toString() {
		return "User [userName=" + userName + ", password=" + password + ", registerTime=" + registerTime + ", sex="
				+ sex + ", userRole=" + userRole + ", idCard=" + idCard + "]";
	}
}

    那么查询 user 表的方法就可以写为这样(不够灵活):

	public User query(String sql) {
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		ResultSet resultSet = null;
		User user = null;

		try {
			connection = JdbcUtils.getConnection();
			System.out.println(sql);
			preparedStatement = connection.prepareStatement(sql);
			resultSet = preparedStatement.executeQuery();

			while (resultSet.next()) {
				user = new User(resultSet.getString(2), resultSet.getString(3), resultSet.getString(4),
						resultSet.getString(5), resultSet.getString(6), resultSet.getString(7));
				System.out.println(user.toString());
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtils.release(preparedStatement, connection, resultSet);
		}
		return user;
	}

Java 反射封装增删改查通用方法_第2张图片

     这样的确可以获取到 user 表,但是这个方法并不能通用。例如:我想查询 student 表时,student 表中字段名与 user 表肯定不一样,这样就会产生错误。所以,这种情况就可以利用 Java 反射来实现。可是,User 类中的变量相当于 user 表中的列名,如果让 User 类将变量名强制写成 user 表中一样,那就显得很局限,不能够通配。那么,就得用到 JDBC 提供的另一个接口了。

(1)ResultSetMetaData 接口

    它用于获取 ResultSet 结果集的元数据,用处是在于从查出的结果集中获取相应的列数、列名等。常用方法如下:

  • getColumnName(int column):获取指定列的名称
  • getColumnCount():返回当前 ResultSet 对象中的列数。
  • getColumnTypeName(int column):检索指定列的数据库特定的类型名称。
  • getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。
  • isNullable(int column):指示指定列中的值是否可以为 null。
  • isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是只读的。

(2)利用 sql 语句添加别名的方式

    比如我要查询 user 表中 ‘小王’ 的详细信息,原本的 sql 语句:

>  SELECT * FROM user WHERE user_name='小王'

    要改为添加别名的方式,注意:别名一定是与User类中定义变量名一致,否则在反射时将找不到字段:

>  SELECT user_name userName,password password,register_time registerTime,sex sex,user_role userRole,id_card idCard FROM user WHERE user_name='小王'

查出来的结果如下图:

Java 反射封装增删改查通用方法_第3张图片

    字段名都与 User 类中的变量名相一致了。

(3)利用 Java 反射给 User 类中的每个属性变量赋予值 .

    那么,经过这几翻的处理,我们的 User 类终于可以匹配数据库了。这个虽说可以实现通用查询,映射到实体类中,但明显在 sql 语句中那么点缺乏简练。整个查询代码如下:

public class JdbcTest {

	/**
	 * 利用 Java 反射机制,写的一个通用查询方法
	 * 
	 * @param sql
	 */
	public  T query(Class clazz, String sql, Object... args) {
		T entity = null;

		Connection connection = null;
		PreparedStatement preparedStatement = null;
		ResultSet resultSet = null;
		User user = null;

		try {
			connection = JdbcUtils.getConnection();
//			System.out.println(sql);
			preparedStatement = connection.prepareStatement(sql);
			if (args != null) {
				for (int i = 0; i < args.length; i++) {
					preparedStatement.setObject(i + 1, args[i]);
				}
			}

			resultSet = preparedStatement.executeQuery();
			ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
			Map values = new HashMap();

	
			if (resultSet.next()) {
				for (int i = 0; i < resultSetMetaData.getColumnCount(); i++) {
					String columnLable = resultSetMetaData.getColumnLabel(i + 1);
					Object columnValue = resultSet.getObject(i + 1);
					values.put(columnLable, columnValue);
				}
			}

			System.out.println("--->数据库:"+values);
			if (values.size() > 0) {
				entity = (T) clazz.newInstance();
				for (Entry entry : values.entrySet()) {
					String fieldName = entry.getKey();
					Object fieldValue = entry.getValue();
					Field field = clazz.getDeclaredField(fieldName);
					field.setAccessible(true);
					field.set(entity, fieldValue);
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtils.release(preparedStatement, connection, resultSet);
		}
		return entity;
	}

	@Test
	public void qurey() {
		String sql = "SELECT user_name userName,password password,register_time registerTime,"
				+ "sex sex,user_role userRole,id_card idCard FROM user WHERE user_name=?";
		User user = query(User.class, sql, "小王");
		System.out.println("--->反射到 User 类中:"+user.toString());
	}
}

(4)BeanUtils 工具包

    BeanUtils 工具包是 Apache 出的一个辅助工具,主要方便对于 JavaBean 进行一系列的操作。例如:

  1. 可以对 JavaBean 的 getter()/setter() 方法进行赋值操作
  2. 可以将Map集合对象直接转为 JavaBean 对象,需要属性名一致
  3. 可以实现两个 JavaBean 对象的拷贝操作

    BeanUtils 工具类的常用方法如下:

  • BeanUtils.setProperty(bean, name, value);实现对象的赋值操作
  • ConvertUtils.register(Converter converter , ..);当需要将String数据转换成引用数据类型(自定义数据类型时),需要使用此方法实现转换
  • BeanUtils.populate(bean,Map);实现将Map拷贝到对象中
  • BeanUtils.copyProperties(newObject,oldObject);实现对象之间的拷贝

    现在我们导入 beanutils.jar 包和一个依赖的 loggin.jar 包:

Java 反射封装增删改查通用方法_第4张图片

    修改上面部分代码:

将                Field field = clazz.getDeclaredField(fieldName);
                    field.setAccessible(true);
                    field.set(entity, fieldValue);

修改为         BeanUtils.setProperty(entity, fieldName, fieldValue);

    运行代码,匹配数据库成功,并反射到 User 类中:

你可能感兴趣的:(#,JavaEE,Java)