JDBC讲解视频(宋红康):https://www.bilibili.com/video/av67955358?p=1
博客详解:https://blog.csdn.net/qq_41112238/article/details/103595239
建一个配置文件 jdbc.properties,好处就是不用在Java代码中将连接写死
写一个工具类JDBCUtils,将对数据库的通用操作封装在这个类里,一个是获取数据库连接操作(getConnection),一个是结束数据库操作后,对资源进行释放(getclose)
public static Connection getConnection(){
//加在载配置文件 (getResource(jdbc.properties) 默认是在src下,所以要把jdbc.properties放在src目录下)
InputStream is =Connection.class.getClassLoader().getResource(jdbc.properties)
Properies 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("drivers")
try {
//加载驱动器,我的配置文件设置的是mysql数据库的驱动器
Class.forName(driverClass);
//这三个参数依照自己的进行修改
Connection conn=DriverManager.getConnection(url,user, password);
} catch (Exception e) {
e.printStackTrace();
}
//返回连接
return conn;
}
public static void getClose(Connection conn,PreparedStatement ps,ResultSet re){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(ps!=null){
try {
ps.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
①编写’‘增删改’'通用方法(增删改操作没有返回结果,所以不需要考虑如何将结果呈现出来)
public class test{
public void parameterMetaData(String sql,Object... params){
Connection connection =null;
PreparedStatement preparedStatement=null;
ResultSet re=null
try {
获取连接对象,getConnection()是上面自己定义的代码
connection = JDBCUtils.getConnection();
//获取PreparedStatement对象
preparedStatement = connection.prepareStatement(sql);
//获取ParameterMetaData参数元数据(只有通过元数据才能得到你的sql中占位符的个数,也就是参数的个数)
ParameterMetaData parameterMetaData = preparedStatement.getParameterMetaData();
//获取sql参数的数量
int parameterCount = parameterMetaData.getParameterCount();
//给参数赋值,注意第一个参数的下标从1开始,而不是从0开始
for(int i=0;i<parameterCount;i++){
preparedStatement.setObject(i+1,params[i]);
}
//执行sql语句
preparedStatement.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
finally{
//关闭连接
JDBCUtils.getClose(connection,preparedStatement,re);
}
}
''增删改''方法测试:
@Test
public void test(){
//增加
parameterMetaData("insert into user values(null,?,?)","bbbbbb","123456");
//删除
parameterMetaData("delete from user where id=?", 27);
//修改
parameterMetaData("update user set name=?,password=? where id=?","lililili","258369",2);
}
}
②编写通用的查询方法(查询操作有返回结果,我们一般将返回结果中的每行数据封装成一个实体对象)
查询操作问题分析 :查询操作其实也就是比’'增删改"多了对返回结果的处理,查询操作是有返回结果的,所以在此之前我们的思想都是一样的,但是在sql语句执行之后,我们就要想办法那么如何对返回结果进行展示呢,我们的思想是用对象来封装返回结果,先通过无参构造方法,构造实体对象,通过手动实现用返回结果的字段名称与实体对象属性的映射来进行封装对象,那如果是对不同的表进行查询操作呢,那么就意味着要用不同实体对象接收查询结果(返回结果的字段名要在实体对象中找到相同的属性名称),也就意味着创建实体对象的时候不能写死,所以这个时候为了对结果的处理我们引用了泛型参数.也就是这个函数用一个泛型参数来接收实体对象类型
实体类User(用来封装结果)
class User{
private Integer id;
private String name;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
实体类Order
class Order{
private Integer orderid;
private String ordername;
@Override
public String toString() {
return "Order{" +
"orderid=" + orderid +
", ordername='" + ordername+ '\'' +
'}';
}
}
有两个表:
user表:id,name
order表:id,ordername (这里order表id字段和Order对象的orderidid不一致的时候,怎么处理,下面会讲到,用sql语句中的别名)
//结果集元数据编写查找通用方法
public class Add{
public <T> List<T> resultSetMetaData(String sql, Object[] params, Class<T> clazz){
//创建List保存要查询的数据
Connection connection=null;
PreparedStatement preparedStatement=null;
ResultSet resultSet=null;
List<T> list = new ArrayList<>();
try {
//获取数据库连接
connection = JDBCUtils.getConnection();
//获取PreparedStatement对象
preparedStatement = connection.prepareStatement(sql);
//获取ParameterMetaData参数元数据
ParameterMetaData parameterMetaData = preparedStatement.getParameterMetaData();
//获取sql参数的数量
int parameterCount = parameterMetaData.getParameterCount();
//给参数赋值
for(int i=0;i<parameterCount;i++){
preparedStatement.setObject(i+1,params[i]);
}
//执行sql语句,并返回结果resultSet
ResultSet resultSet = preparedStatement.executeQuery();
//获取ResultSetMetaData结果集元数据
ResultSetMetaData metaData = resultSet.getMetaData();
//通过结果集元数据获取字段数量,因为你想要查询的字段数量不一样,你可能查询的是两列字段的结果,也有可能是全部字段的结果,这个时候只能通过元数据的getColumnCount进行获取
int columnCount = metaData.getColumnCount();
//每循环一个代表查询出一行数据,resultSet指针一开始指向第一行返回结果的上面,所以要next()来获取第一行返回结果
while(resultSet.next()){
//操作的库不一样,要封装的对象类型也不一样,所以只能用泛型类进行传参
T t = clazz.newInstance(); //相当于通过无参构造函数获取一个实体对象
for(int i=0;i<columnCount;i++){
//通过字段序号获取字段数据
Object value = resultSet.getObject(i+1);
//通过字段序号获取字段名称,通过元数据进行获取
String columnName = metaData.getColumnName(i+1);
//如果我定义的实体类属性名称与表的字段名称就是不一样怎么办呢,我们可以借助于别名,也就是在sql语句上下手,下面的函数调用的时候会进行展示
// String columnLabel = metaData.getColumnLabel(i+1);
//结果赋值给javabean对象,通过映射的方法,就是通过返回结果的字段名称映射到实体对象的属性(如果起了别名也可以通过别名与属性名进行映射,也就是字段名称不是说必须与对象属性名一致,也可以是别名与对象属性名一致)
Field declaredField = clazz.getDeclaredField(columnName);
// 用别名 Field declaredField = clazz.getDeclaredField(columnLabel);
declaredField.setAccessible(true); //属性可修改
declaredField.set(t,value);
}
/
//将javabean保存到List
list.add(t);
}
} catch (Exception e) {
e.printStackTrace();
}
finally{
//关闭连接
JDBCUtils.getClose(connection,preparedStatement,re);
}
return list;
}
}
@Test
public void test(){
user_sql="select * from user where id=? and name=?"
List<User> users = resultSetMetaData(user_sql, new Object[]{"1", "tom"}, User.class);
for (User user:users) {
System.out.println(user.toString());
}
//下面是当表字段名称与实体对象属性不一致的时候,用别名
order_sql="select id as orderid from order where ordername=? "
List<Order> order = resultSetMetaData(order_sql, new Object[]{"糖"}, Order.class);
}
}