MySQL高级
1. 通用查询方法实现
1.1 技术点分析
需求:
用户提供SQL语句,并且提供对应SQL语句的使用参数,同时告知方法需要返回数据类型是哪一个类型。
举例说明:
1. table Student ==> SQL, Parameter, 【告知当前查询数据类型为Student类型】
2. table Employee ==> SQL, Parameter, 【查询结果应该也是一个Employee对象】
3. table Worker ==> SQL, Parameter, 【查询结果应该也是一个Worker对象】
ORM ==> Object-relational mapping (ORM, O/RM, and O/R mapping tool
对象关系映射 对象 <==> 数据表 映射关系
数据库相关框架:
MyBatis Hibernate MyBatis-Plus DbUtils
缺少的技术点:
是否存在泛型期望???
存在,代码需要支持任意数据类型,但是要求数据类型一致化。
是否存在对Class的需求???
需要Class提供当前数据类型,并且可以利用反射支持类对象创建,成员变量赋值取值
是否需要统一操作获取查询结果集字段名称???
需要获取字段名称,映射类对象成员变量名字
赋值操作,类型转换??? Object ==> 指定类型
提供第三方工具类,辅助完成任意类型赋值成员变量操作过程。
1.2 泛型和Class对象解决数据类型问题
package com.qfedu.a_utilTest;
import java.lang.reflect.InvocationTargetException;
public class Demo1 {
public static void main(String[] args) {
Class<Student> studentClass = Student.class;
Student student = getInstance(studentClass);
String s = getInstance(String.class);
Demo1 demo1 = getInstance(Demo1.class);
SingleDog singleDog = getInstance(SingleDog.class);
}
public static <T> T getInstance(Class<T> cls) {
T t = null;
try {
t = cls.getConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException
| InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
return t;
}
}
1.3 赋值问题解决 BeanUtils工具类
package com.qfedu.a_utilTest;
import org.apache.commons.beanutils.BeanUtils;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
public class Demo2 {
public static void main(String[] args)
throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
Student student = new Student();
System.out.println(student);
BeanUtils.setProperty(student, "id", "10");
BeanUtils.setProperty(student, "age", -106);
BeanUtils.setProperty(student, "name", "张三");
BeanUtils.setProperty(student, "gender", "false");
BeanUtils.setProperty(student, "score", "100");
BeanUtils.setProperty(student, "info", "XXXXXXXXXXXXXXXXX");
System.out.println(student);
System.out.println(BeanUtils.getProperty(student, "id"));
System.out.println(BeanUtils.getProperty(student, "name"));
System.out.println(BeanUtils.getProperty(student, "age"));
System.out.println(BeanUtils.getProperty(student, "gender"));
System.out.println(BeanUtils.getProperty(student, "score"));
System.out.println(BeanUtils.getProperty(student, "info"));
System.out.println();
Student student1 = new Student();
System.out.println(student1);
BeanUtils.copyProperties(student1, student);
System.out.println(student1);
System.out.println(student.hashCode());
System.out.println(student1.hashCode());
HashMap<String, String> map = new HashMap<>();
map.put("id", "290");
map.put("name", "李四");
map.put("gender", "false");
map.put("score", "59");
map.put("info", "菜的一批~~~");
map.put("married", "false");
Student student2 = new Student();
BeanUtils.populate(student2, map);
System.out.println(student2);
}
}
1.4 查询结果集字段名获取
package com.qfedu.a_utilTest;
import util.JdbcUtil;
import java.sql.*;
public class Demo3 {
public static void main(String[] args) throws SQLException {
Connection connection = JdbcUtil.getConnection();
String sql = "select * from student_info.student where id = 1";
PreparedStatement statement = connection.prepareStatement(sql);
ResultSet resultSet = statement.executeQuery();
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
System.out.println(columnCount);
System.out.println(metaData.getColumnName(1));
System.out.println(metaData.getColumnName(2));
System.out.println(metaData.getColumnName(3));
System.out.println(metaData.getColumnName(4));
System.out.println(metaData.getColumnName(5)) ;
System.out.println(metaData.getColumnName(6));
if (resultSet.next()) {
System.out.println(resultSet.getObject(metaData.getColumnName(1)));
System.out.println(resultSet.getObject(metaData.getColumnName(2)));
System.out.println(resultSet.getObject(metaData.getColumnName(3)));
System.out.println(resultSet.getObject(metaData.getColumnName(4)));
System.out.println(resultSet.getObject(metaData.getColumnName(5)));
System.out.println(resultSet.getObject(metaData.getColumnName(6)));
}
System.out.println(resultSet);
JdbcUtil.close(connection, statement, resultSet);
}
}
1.5 通用查询方法声明分析
方法参数:
String sql, Class<T> cls, Object... parameters;
sql 目前需要进行查询操作的SQL语句
cls 带有泛型,用于约束当前查询的目标数据类型是哪一个,同时提供Class对象,可以利用反射完成对象创建,赋值成
员变量操作。
parameters 对应当前SQL语句的参数
方法名:
query
返回值类型:
1. 泛型一定有
2. 返回结果是一个T对应类型对象还是一组对象???
List<T>
方法声明:
public <T> List<T> query(String sql, Class<T> cls, Object... parameters);
public <T> List<T> query(String sql, Class<T> cls, Object... parameters) {
if (null == sql || null == cls) {
throw new IllegalArgumentException("SQL or cls is null");
}
ResultSet resultSet = null;
PreparedStatement statement = null;
List<T> list = new ArrayList<>();
Connection connection = JdbcUtil.getConnection();
try {
statement = connection.prepareStatement(sql);
int parameterCount = statement.getParameterMetaData().getParameterCount();
if (!(0 == parameterCount || null == parameters || parameterCount != parameters.length)) {
for (int i = 0; i < parameters.length; i++) {
statement.setObject(i + 1, parameters[i]);
}
}
resultSet = statement.executeQuery();
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
while (resultSet.next()) {
T t = cls.getConstructor().newInstance();
for (int i = 1; i <= columnCount; i++) {
String fieldName = metaData.getColumnName(i);
Object value = resultSet.getObject(fieldName);
BeanUtils.setProperty(t, fieldName, value);
}
list.add(t);
}
} catch (SQLException | NoSuchMethodException | InstantiationException | IllegalAccessException
| InvocationTargetException e) {
e.printStackTrace();
} finally {
JdbcUtil.close(connection, statement, resultSet);
}
return list.size() == 0 ? null : list;
}
2. 数据库连接池
2.1 现有操作数据库的问题
数据库操作使用Connection对象,在每一次执行SQL语句之后,都进行了关闭操作。在目前情况下,如果不关闭,会导致资源浪费,内存冗余。关闭资源习惯需要养成。
打开关闭数据库操作过多针对资源也是浪费使用。
类似于线程池操作的情况,满足用户使用数据库资源,同时降低数据库在创建和关闭时资源浪费。
2.2 需要考虑的参数和代理思想引入
数据库连接所需必要资源:
1. driverClass
2. jdbcUrl
3. username
4. password
关于数据库的性能配置
1. 初始化数据库连接池对象Connection个数
2. 阈值最多数据库连接对象Connection个数和最小个数
3. 等待时间
4. 每一个Connection对象最大的Statement个数
Connection对象需要结构存储
底层参数Connection对象,采用的形式是链表结构,增删快
代理
用户依然使用getConnection获取数据库连接对象,同时使用close关闭资源。操作流程没有变化。
close方法在数据库连接池中不是真正的关闭当前Connection对象,而是将Connection对象归还到底层结构。
2.3 Druid数据库连接池使用
# druid.properties文件
# 文件名 druid.properties 存储在src目录下
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/student_info?useSSL=false
username=root
password=123456
# 初始化数据库连接池容量
initialSize=10
# 最大容量
maxActive=30
# TimeOut 等待超时时间
maxWait=2000
package util;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
public class JdbcUtil {
private static DataSource ds;
static {
try {
Properties properties = new Properties();
properties.load(new FileInputStream("./src/druid.properties"));
ds = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
Connection connection = null;
try {
connection = ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
public static void close(Connection conn) {
close(conn, null, null);
}
public static void close(Connection conn, Statement st) {
close(conn, st, null);
}
public static void close(Connection conn, Statement st, ResultSet rs) {
try {
close(rs, st, conn);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void close(AutoCloseable... res) throws Exception {
for (AutoCloseable re : res) {
if (re != null) {
re.close();
}
}
}
}