一:版本一.这种存在一个问题就是每执行一次操作都会创建一次Connection链接和且释放一次链接

1:创建pojo对象(OR映射,一个pojo类对应一张数据库表)

 
 package com.yinfu.dao;

  public class Employee {

      private int id;
private String name;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", password=" + password + "]";
}
public Employee(int id, String name, String password) {
super();
this.id = id;
this.name = name;
this.password = password;
}
public Employee() {
super();
}
}

pojo对象

2:创建数据库连接用的数据文件,用于外界读取数据(properties文件):

driver=com.mysql.jdbc.Driver jdbcUrl=jdbc:mysql://localhost:3306/test user=root password=song12345

3:创建数据库连接和关闭连接的工具类(被重复使用的方法可以写在工具类中):

 package com.yinfu.utils;

 import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
/**
* JDBC的工具类,封装了jdbc的一些方法
* @author lusong
*
*/
public class JDBCUtils { //关闭jdbc的链接
/**
* 关闭statement和connection
* @param ps
* @param conn
*/
public static void release(PreparedStatement ps, Connection conn){
try {
if(ps != null){
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(conn != null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void release(ResultSet result,PreparedStatement ps, Connection conn){
try {
if(result != null){
result.close();
}
} catch (SQLException e1) {
e1.printStackTrace();
}finally{
try {
if(ps != null){
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(conn != null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
} } //获取jdbc的链接
/**
* 用于创建jdbc链接的工具类对象
* @return
*/
public static Connection getConnetions() {
Connection conn = null;
String driverClass = null;
String jdbcUrl = null;
String user = null;
String password = null; try {
//读取配置文件中的配置
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(is);
driverClass = properties.getProperty("driver");
jdbcUrl = properties.getProperty("jdbcUrl");
user = properties.getProperty("user");
password = properties.getProperty("password");
//注册驱动程序
Class.forName(driverClass);
//实际应该这样写(由于对应的应用程序中有一个对应的静态代码块,自动回将驱动的类对象进行驱动加载)
//DriverManager.registerDriver((Driver) Class.forName(driverClass).newInstance()); conn = DriverManager.getConnection(jdbcUrl,user,password); } catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
}

4:用Junit测试实现的JDBC实现数据库的增删改查操作:

 package com.yinfu.test;

 import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties; import org.junit.Test; import com.yinfu.dao.Employee;
import com.yinfu.utils.JDBCUtils; public class JDBCTest { @Test
public void testUpdate(){
//曾
String sql = "insert into employee (Id,Name,Password) values (1,'wangba',131)";
//删
//String sql = "delete from employee where id = 1";
//改
//String sql = "update employee set name = 'fuck' where id = 2";
//查
String sqlQuery = "select * from employee";
update(sql);
testQueryObject(sqlQuery);
} public void testQueryObject(String sql){
Employee employee = null;
List<Employee> list = new ArrayList();
Connection conn = null;
PreparedStatement ps = null;
ResultSet result = null;
try {
//创建连接
conn = JDBCUtils.getConnetions();
//创建prepareStatement对象,用于执行SQL
ps = conn.prepareStatement(sql);
//获取查询结果集
result = ps.executeQuery();
while(result.next()){
employee = new Employee(result.getInt(1),result.getString(2),result.getString(3));
list.add(employee);
}
System.out.println(list);
} catch (Exception e) {
e.printStackTrace();
}finally{
JDBCUtils.release(result, ps, conn);
}
} public void update(String sql){
Connection conn = null;
PreparedStatement ps = null;
try {
//创建数据库连接
conn = JDBCUtils.getConnetions();
//创建执行SQL的prepareStatement对象
ps = conn.prepareStatement(sql);
//用于增删改操作
int result = ps.executeUpdate();
System.out.println(result);
} catch (Exception e) {
System.out.println("出现异常1="+e.toString());
}finally{
JDBCUtils.release(ps, conn);
} }
}

Statement 和PrepareStatement的区别:

首先是执行SQL的方法:

statement: 

  Class.forName(jdbcDriver);

  Connection conn = DriverManager.getConnection(jdbcUrl,userName,password);

  String sql = "insert into employee () values ('','','')"

  Statement statement = conn.createStatement();

  statement.executeUpdate(sql);

  其中的SQL语句中若有要动态输入的数据时,需要用字符串拼接SQL,难以维护容易出错。

prepareStatement:

  Class.forName(jdbcDriver);

  Connection conn = DriverManager.getConnection(jdbcUrl,userName,password);

  String sql = "insert into employee () values ('','','')"

  PrepareStatement ps = conn.prepareStatement(sql);

  statement.executeUpdate();

  其中的SQL语句中要是有动态输入的数据时,可以用占位'?'符来代替:

  String sql = "insert into employee () values (?,?,?)";

  然后用prepareStatement接口中的方法来动态赋值:

  ps.setXXX(int paramIndex ,Object value);//参数含义:占位符对应的索引值,该索引值对应的参数值;

2:(利用反射工具类)升级版查询:利用反射和JDBC元数据编写通用的查询单条记录方法(ResultSetMetaData是结果集的元数据对象):

1:创建反射工具类:

 package com.yinfu.utils;

 import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; /**
* 反射的 Utils 函数集合 提供访问私有变量, 获取泛型类型 Class, 提取集合中元素属性等 Utils 函数
*
* @author Administrator
*
*/
public class ReflectionUtils { /**
* 通过反射, 获得定义 Class 时声明的父类的泛型参数的类型 如: public EmployeeDao extends
* BaseDao<Employee, String>
*
* @param clazz
* @param index
* @return
*/
@SuppressWarnings("unchecked")
public static Class getSuperClassGenricType(Class clazz, int index) {
Type genType = clazz.getGenericSuperclass(); if (!(genType instanceof ParameterizedType)) {
return Object.class;
} Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); if (index >= params.length || index < 0) {
return Object.class;
} if (!(params[index] instanceof Class)) {
return Object.class;
} return (Class) params[index];
} /**
* 通过反射, 获得 Class 定义中声明的父类的泛型参数类型 如: public EmployeeDao extends
* BaseDao<Employee, String>
*
* @param <T>
* @param clazz
* @return
*/
@SuppressWarnings("unchecked")
public static <T> Class<T> getSuperGenericType(Class clazz) {
return getSuperClassGenricType(clazz, 0);
} /**
* 循环向上转型, 获取对象的 DeclaredMethod
*
* @param object
* @param methodName
* @param parameterTypes
* @return
*/
public static Method getDeclaredMethod(Object object, String methodName, Class<?>[] parameterTypes) { for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass
.getSuperclass()) {
try {
// superClass.getMethod(methodName, parameterTypes);
return superClass.getDeclaredMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
// Method 不在当前类定义, 继续向上转型
}
// ..
} return null;
} /**
* 使 filed 变为可访问
*
* @param field
*/
public static void makeAccessible(Field field) {
if (!Modifier.isPublic(field.getModifiers())) {
field.setAccessible(true);
}
} /**
* 循环向上转型, 获取对象的 DeclaredField
*
* @param object
* @param filedName
* @return
*/
public static Field getDeclaredField(Object object, String filedName) { for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass
.getSuperclass()) {
try {
return superClass.getDeclaredField(filedName);
} catch (NoSuchFieldException e) {
// Field 不在当前类定义, 继续向上转型
}
}
return null;
} /**
* 直接调用对象方法, 而忽略修饰符(private, protected)
*
* @param object
* @param methodName
* @param parameterTypes
* @param parameters
* @return
* @throws InvocationTargetException
* @throws IllegalArgumentException
*/
public static Object invokeMethod(Object object, String methodName, Class<?>[] parameterTypes, Object[] parameters)
throws InvocationTargetException { Method method = getDeclaredMethod(object, methodName, parameterTypes); if (method == null) {
throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + object + "]");
} method.setAccessible(true); try {
return method.invoke(object, parameters);
} catch (IllegalAccessException e) {
System.out.println("不可能抛出的异常");
} return null;
} /**
* 直接设置对象属性值, 忽略 private/protected 修饰符, 也不经过 setter
*
* @param object
* @param fieldName
* @param value
*/
public static void setFieldValue(Object object, String fieldName, Object value) {
Field field = getDeclaredField(object, fieldName); if (field == null)
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]"); makeAccessible(field); try {
field.set(object, value);
} catch (IllegalAccessException e) {
System.out.println("不可能抛出的异常");
}
} /**
* 直接读取对象的属性值, 忽略 private/protected 修饰符, 也不经过 getter
*
* @param object
* @param fieldName
* @return
*/
public static Object getFieldValue(Object object, String fieldName) {
Field field = getDeclaredField(object, fieldName); if (field == null)
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]"); makeAccessible(field); Object result = null; try {
result = field.get(object);
} catch (IllegalAccessException e) {
System.out.println("不可能抛出的异常");
} return result;
}
}

反射工具类

2:编写通用查询:

 package com.yinfu.test;

 import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties; import org.junit.Test; import com.yinfu.dao.Employee;
import com.yinfu.utils.JDBCUtils;
import com.yinfu.utils.ReflectionUtils; public class JDBCTest { @Test
public void testUpdate(){
//查
String sqlQuery = "select id, name, password from employee where name = ?";
Object employee = testQueryObject(Employee.class,sqlQuery,"zhangsan");
System.out.println("利用反射="+employee);
} public <T> T testQueryObject(Class<T> clazz, String sql, Object ... args){
T object = null;
Map<String, Object> map = new HashMap<String, Object>();
Connection conn = null;
PreparedStatement ps = null;
ResultSet resultSet = null;
try {
//创建连接
conn = JDBCUtils.getConnetions();
//创建prepareStatement对象,用于执行SQL
ps = conn.prepareStatement(sql);
//将参数赋值到sql的所需参数中
for(int i = 0 ; i < args.length ; i++){
ps.setObject(i+1, args[i]);
}
//一:根据SQL语句和传入的参数得到结果集,此结果集中全部是纯数据值,不带列名;
resultSet = ps.executeQuery();
//二:利用ResultSet对象得到ResultSetMetaData对象jdbc的元数据,根据此对象可以知道SQL语句查询了哪些列,以及列的别名是什么(具体参考JDBC的API进行学习)
ResultSetMetaData rsmd = resultSet.getMetaData();
while(resultSet.next()){
//把列名的别名和列值分别取出来放到map中作为键值出现(resultSet和rsmd结合得到的就是一个表,和数据库表一样),由ResultSetMetaData得到每一列的别名, //由ResultSet 得到对应的值
for(int i=0;i<rsmd.getColumnCount();i++){
String columnLabel = rsmd.getColumnLabel(i+1);
Object columnValue = resultSet.getObject(columnLabel);
map.put(columnLabel, columnValue);
}
}
//利用反射创建class对应的对象
object = (T) clazz.newInstance();
//遍历map对象,用反射填充对象属性值
for(Map.Entry<String, Object> entry : map.entrySet()){
String fieldName = entry.getKey();
Object fieldValue = entry.getValue();
//利用反射工具類(属性名对应map的key值,属性名对应map的value值)
ReflectionUtils.setFieldValue(object, fieldName, fieldValue);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
JDBCUtils.release(resultSet, ps, conn);
}
return object;
}
}

3:利用BeanUtils工具类实现查询多条记录(添加commons-beanutils.jar和commons-logging.jar):

 package com.yinfu.test;

 import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties; import org.apache.commons.beanutils.BeanUtils;
import org.junit.Test; import com.yinfu.dao.Employee;
import com.yinfu.utils.JDBCUtils;
import com.yinfu.utils.ReflectionUtils; public class JDBCTest { @Test
public void testUpdate(){
//查多条
String sqlQueryList = "select id, name, password from employee";
List<Employee> testQueryList = testQueryList(Employee.class,sqlQueryList);
System.out.println("查询多条:"+testQueryList); } //查询多条记录
public <T> List<T> testQueryList(Class<T> clazz, String sql, Object ...args ){
//用于接收返回值
T object = null;
List<T> list = new ArrayList<>();
Connection conn = null;
PreparedStatement rs = null;
ResultSet resultSet = null;
try {
//获取数据库连接
conn = JDBCUtils.getConnetions();
rs = conn.prepareStatement(sql);
//填充占位符
for(int i = 0; i < args.length; i++){
rs.setObject(i+1, args[i]);
}
//获取结果集
resultSet = rs.executeQuery();
//1:准备一个List<Map<String, Object>>集合,其中key为列名,value为列值,每一个map对应一条记录
List<Map<String, Object>> listMap = new ArrayList<>();
//2:得到jdbc的元数据
ResultSetMetaData rsmd = rs.getMetaData();
while(resultSet.next()){
Map<String, Object> map = new HashMap<>();
for(int i = 0; i < rsmd.getColumnCount(); i++){
//游标是从1开始的
String columnLabel = rsmd.getColumnLabel(i+1);
Object columnValue = resultSet.getObject(columnLabel);
map.put(columnLabel, columnValue);
}
//3:把一条记录map放入到listMap中
listMap.add(map);
} /*//上面一段代码可以这样写
List<String> labelList = getColumnLabels(resultSet);
while(resultSet.next()){
Map<String, Object> map = new HashMap<>();
for(String columnLabel : labelList){
Object columnValue = resultSet.getObject(columnLabel);
map.put(columnLabel, columnValue);
}
//3:把一条记录map放入到listMap中
listMap.add(map);
}*/ //4:遍历listMap集合,把其中的每一个map都转换成对应的Class对象,并放到list中进行返回
if(listMap.size()>0){
for(Map<String, Object> mapObj : listMap){
//有记录就通过反射得到对应的类对象
object = clazz.newInstance();
for(Map.Entry<String, Object> entry : mapObj.entrySet()){
String propertyName = entry.getKey();
Object propertyValue = entry.getValue();
//利用工具类beanutils进行实体类转换
BeanUtils.setProperty(object, propertyName, propertyValue);
}
list.add(object);
}
} } catch (Exception e) {
e.printStackTrace();
} return list;
} private List<String> getColumnLabels(ResultSet resultSet) throws SQLException{
ResultSetMetaData rsmd = resultSet.getMetaData();
List<String> list = new ArrayList<>();
for(int i = 0; i<rsmd.getColumnCount(); i++){
list.add(rsmd.getColumnLabel(i+1));
}
return list;
}
}

查询多条记录

4:可以用获取PrepareStatement的另一个重载方法得到,然后再用此对象的getGeneratedKeys()方法得到插入的数据时自动生成的ID的结果集,此结果集就一列,列名为:GENERATED_K。

用jdbc连接数据库并简单执行SQL语句的更多相关文章

  1. JDBC进阶之PreparedStatement执行SQL语句(MySQL)

    一.什么是PreparedStatement           参阅Java API文档,我们可以知道,PreparedStatement是Statement的子接口(如图所示),表示预编译的 SQ ...

  2. JDBC连接MYSQL,批量执行SQL语句或在执行一个SQL语句之前执行一个SQL语句

    conn = MysqlJdbcUtils.getConnection(); Statement ps=conn.createStatement(); ps.addBatch("trunca ...

  3. BIML 101 - ETL数据清洗 系列 - BIML 快速入门教程 - 连接数据库执行SQL语句

    BIML 101 - BIML 快速入门教程 第一节 连接数据库执行SQL语句 本小节将用BIML建一个简单的可以执行的包. 新建一个biml文件,贴入下面的代码 1 <Biml xmlns=& ...

  4. JDBC详解系列(四)之建立Stament和执行SQL语句

    建立Stament   在获得连接之后,我们就可以跟数据库进行交互了.   在JDBC中,我们发送SQL语句到数据库这些操作时通过Stament,Preparement,CallableStateme ...

  5. JDBC中执行SQL语句的方式

    一.执行DDL.DML语句 DDL.DML分别表示数据库定义语言.数据库操纵语言,操控这两种语言应该使用Statement对象的executeUpdate方法. 代码如下: public static ...

  6. 10.1(java学习笔记)JDBC基本操作(连接,执行SQL语句,获取结果集)

    一.JDBC JDBC的全称是java database connection java数据库连接. 在java中需要对数据库进行一系列的操作,这时就需要使用JDBC. sun公司制定了关于数据库操作 ...

  7. JDBC课程2--实现Statement(用于执行SQL语句)--使用自定义的JDBCTools的工具类静态方法,包括insert/update/delete三合一

    /**JDBC课程2--实现Statement(用于执行SQL语句) * 1.Statement :用于执行SQL语句的对象: * 1): 通过Connection 的createStatement( ...

  8. JDBC第一篇--【介绍JDBC、使用JDBC连接数据库、简单的工具类】

    1.什么是JDBC JDBC全称为:Java Data Base Connectivity,它是可以执行SQL语句的Java API 2.为什么我们要用JDBC 市面上有非常多的数据库,本来我们是需要 ...

  9. JDBC【介绍JDBC、使用JDBC连接数据库、简单的工具类】

    1.什么是JDBC JDBC全称为:Java Data Base Connectivity,它是可以执行SQL语句的Java API 2.为什么我们要用JDBC 市面上有非常多的数据库,本来我们是需要 ...

随机推荐

  1. hihocoder 1579(排列组合)

    题意 给出一个长度为n的字符串的sa数组,n<=1e5,问有多少种不同的字符串的sa数组正好是输入的sa数组(字符串每个位置都是小写字母) 分析 sa数组描述的是字符的大小关系,而不是确切的字符 ...

  2. java类中资源加载顺序

    根据优先级别从高到低依次为:1.父类中的静态代码块(static);2.自身的静态代码块;3.父类中的的普通代码块;4.父类的构造方法;5.自身的普通代码块;6.自身的构造方法; 下面是一个测试 结果 ...

  3. mybatis几种开发方式

    mybatis是比较轻巧的半自动化的CRM框架,它有几种开发方式,现今张列于此: 一.注解方式:在接口方法上面写SQL语句,有点类似springdataJPA 的query sql 语句 范例 @se ...

  4. HDU 4279 Number(找规律)

    Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  5. 如何在Win7 x64上的配置32位的PostgreSQL ODBC数据源

    在Win7 x64下安装最新版的PostgreSQL 9.x 后,从其官网下载最新的 ODBC驱动,分为普通的32位和64位版本,正常安装后,从已安装软件列表里可以看到两个版本的驱动都已经正确显示出来 ...

  6. 【转】AOP

    原文:http://blog.csdn.net/zhoudaxia/article/details/38502347 .---------------------------------------- ...

  7. 【安卓笔记】抽屉式布局----DrawerLayout

    效果例如以下: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hkamo=/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...

  8. RxJava系列之中的一个 初识Rxjava

    1.简单介绍 基础知识 响应式代码的基本组成部分是Observables和Subscribers(事实上Observer才是最小的构建块,但实践中使用最多的是Subscriber.由于Subscrib ...

  9. MySQL基础笔记(五) 视图

    一.什么是视图 视图是一个虚拟表.也就是说,视图在外观和行为上都类似于表,但它不需要实际的物理存储,只保存了视图定义(查询语句). 视图由select查询所定义 -- 当创建一个视图时,实际上是在数据 ...

  10. React笔记

    React JS Tutorials for Beginners - 1 - Getting Started https://www.youtube.com/watch?v=-AbaV3nrw6E&a ...