JDBC

具体连接数据库的包我们可以通过官网下载,也可以通过在安装的数据库里边找到。
连接数据库的一个包,可以通过这个包,我们通过包提供的封装类,完成连接数据库指令操作。

创建一个JDBC

// 连接mysql
    
    public class JDBC{
        public static void main(String [] args) throws ClassNotFoundException{
            //1加载驱动
            Class.forName("com.mysql.jdbc.Driver");//固定语法,加载驱动,注意mysql5.0和8.0直接驱动连接有差别.5.0的不需要有cj,也就是com.mysql.jdbc.Driver,但是8.0的是com.mysql.cj.jdbc.Driver
            
            //2用户信息,url
            String url = "jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=utf8&useSSL=true";
            String username = "root";
            String password = "a"; 
            //3连接成功,数据库对象 Connection 代表数据库
           Connection connection = DriverManager.getConnection(url,username,password); 
            //4执行sql对象  Statement 执行sql对象的
         Statement statement = connection.createStatement();   
            //执行sql对象去执行sql的可能存在的结果
            String sql = "你要写的sql语句"
    
            ResuletSet resultSet = statement.executeQuery(sql);//返回结果集,结果集中封装了我们全部查询出来的结果
            while(resultSet.next()){
                //以下全为表中的列字段
                System.out.println("id= " resultSet.getObject("id"));
                   System.out.println("name= " resultSet.getObject("name"));
                   System.out.println("pwd= " resultSet.getObject("pwd"));
                   System.out.println("email= " resultSet.getObject("email"));
                   System.out.println("birth= " resultSet.getObject("brithday"));
                
            }
            
                    //释放连接,关闭。
            resultSet.close();
            statement.close();
            connection.close();
    
        }
    }

步骤总结:

  1. 加载驱动
  2. 连接数据库DriverManager
  3. 获取执行sql的对象Statement
  4. 返回获得的结果集(list)
  5. 释放连接

DriverManager

Class.forName("com.mysql.jdbc.Driver");

   Connection connection = DriverManager.getConnection(url,username,password);//连接数据库
//事务以及自动提交都可以通过这个操作

Url

String url = "jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=utf8&useSSL=true";
// mysql 3306 
// jdbc:mysql://主机地址:端口号/数据库名?参数1&参数2.。。。
//oracle 1521
//jdbc:oracle:thin:@localhost:1521:表名?

Statement

//4执行sql对象  Statement 执行sql对象的
    Statement statement = connection.createStatement();   
	statement.executeQuery();// 查询操作返回ResultSet
	statement.execute();//执行任何Sql
	statement.executeUpdate();//更新,插入删除,都是通过这个。

ResultSet查询的结果集:封装了所有的查询结果

获得指定的数据类型

ResuletSet resultSet = statement.executeQuery(sql);//返回结果集,结果集中封装了我们全部查询出来的结果
//如果不知道列类型的话我们就使用
resultSet.getObject();
//知道的话
resultSet.getString();
resultSet.getInt();
resultSet.getFloat();
....

遍历指针

resultSet.beforeFirst();//移动到最前边
resultSet.afterLast();//移动到最后边
resultSet.next();//移动到下一个数据
resultSet.previous();//移动到前一行
resultSet.absolute(row);//移动到指定行

释放资源:必须要做的

resultSet.close();
   statement.close();
   connection.close();

工具类

创建一个JDBC链接的工具类(oracle)

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;
    
    public class DBHelper {
    	//加载成功,在整个程序中,只需要加载在一次就好了
        //放到静态快里边:因为静态快,自动执行,并且只执行一次
    	static {
    		try {
    			Class.forName(MyProperties.getInstance().getProperty("driverClass"));
    		} catch (ClassNotFoundException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}//静态方法,可以不实例化,而直接调用
    		
    	}
    
    	//获取连接这一段代码,太长了,对此我们封装一下
    	public Connection getCon() {
    		Connection conn = null;
    		//在这里,连接地址,用户名,和密码,对于不同的用户,可能不一样
    		//我们可以将这个三个东西,作为配置项,配置到程序中
    		try {
    			conn = DriverManager.getConnection(MyProperties.getInstance().getProperty("url"),
    					MyProperties.getInstance());
    		} catch (SQLException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		return conn;
    	}
    	/**
    	 * 增删改
    	 * @param sql 要执行的语句
    	 * @param params 要注入的参数
    	 * @return
    	 */
    	public int doUpdate(String sql,List<Object> params) {
    		//定义返回值
    		int result = -1;
    		try {
    			//获取连接
    			Connection conn = getCon();
    			//创建预处理语句对象
    			PreparedStatement ps = conn.prepareStatement(sql);
    			//如果有问号,有参数,要注入参数
    			doParams(ps,params);
    			//执行
    			result = ps.executeUpdate();
    			//关闭各种连接,接口
    			closeAll(conn,null,ps);
    		} catch (SQLException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		//最终返回数据
    		return result;
    	}
    	
    	/**
    	 * 查询语句
    	 * @param sql
    	 * @param params
    	 * @return
    	 */
    	public List<Map<String,Object>> findAll(String sql,List<Object>params){
    		List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
    		try {
    			//获取连接
    			Connection conn = getCon();
    			//创建预处理语句对象
    			PreparedStatement ps = conn.prepareStatement(sql);
    			//如果有问号,有参数,要注入参数
    			doParams(ps, params);
    			//执行这里开始不一样
    			ResultSet rs = ps.executeQuery();
    			//我们要将resultSet里边的值,转化为List<Map<String,Object>>
    			//Map<String,Object> 键值对     键  : 表的字段  值:这个字段对应的值
    			ResultSetMetaData rsmd =rs.getMetaData();
    			//我们将所有的列名,存到一个数组中
    			String [] cnames = new String [rsmd.getColumnCount()];
    			for(int i =0 ;i<cnames.length;i++) {
    				cnames[i] = rsmd.getColumnName(i+1);
    			}
    			//开始获得数据
    			while (rs.next()) {
    				//创建map对象
    				Map<String,Object> map = new HashMap<String, Object>();
    				for(int i =0;i<cnames.length;i++) {
    				
    					if(rs.getObject(cnames[i])== null){
    						map.put(cnames[i].toLowerCase(), "");
    						continue;
    					}
    					if("oracle.sql.BLOB".equals(rs.getObject(cnames[i]).getClass().getName())){
    						map.put(cnames[i].toLowerCase(), rs.getBytes(cnames[i]));
    					}else{
    					//键  转换为小写     值  
    	map.put(cnames[i].toLowerCase(),rs.getObject(cnames[i]));
    				    }
    					
    				}
    				//将map添加到list中
    				list.add(map);
    			}
    			//关闭
    			closeAll(conn,rs,ps);
    		} catch (SQLException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		return list;
    		
    		
    		}
    	
    	public List<Map<String,Object>> findAll(String sql,Object...params){
    		List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
    		try {
    			//获取连接
    			Connection conn = getCon();
    			//创建预处理语句对象
    			PreparedStatement ps = conn.prepareStatement(sql);
    			//如果有问号,有参数,要注入参数
    			doParams(ps, params);
    			
    			//执行这里开始不一样
    			ResultSet rs = ps.executeQuery();
    			//我们要将resultSet里边的值,转化为List<Map<String,Object>>
    			//Map<String,Object> 键值对     键  : 表的字段  值:这个字段对应的值
    			ResultSetMetaData rsmd =rs.getMetaData();
    			//我们将所有的列名,存到一个数组中
    			String [] cnames = new String [rsmd.getColumnCount()];
    			for(int i =0 ;i<cnames.length;i++) {
    				cnames[i] = rsmd.getColumnName(i+1);
    			}
    			//开始获得数据
    			while (rs.next()) {
    				//创建map对象
    				Map<String,Object> map = new HashMap<String, Object>();
    				for(int i =0;i<cnames.length;i++) {
    					// 键          转为小写    值
    					//对于blob 的值,我们这里要区分一下
    					if(rs.getObject(cnames[i])== null){
    						map.put(cnames[i].toLowerCase(), "");
    						continue;
    					}
    //					System.out.println(rs.getObject(cnames[i]).getClass().getName());
    					
    					
    					if("oracle.sql.BLOB".equals(rs.getObject(cnames[i]).getClass().getName())){
    						map.put(cnames[i].toLowerCase(), rs.getBytes(cnames[i]));
    					}else{
    					//键  转换为小写     值  
    					map.put(cnames[i].toLowerCase(),rs.getObject(cnames[i]));
    				    }
    				}
    				//将map添加到list中
    				list.add(map);
    			}
    		
    		} catch (SQLException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		return list;
    		}
    	
    	//注入参数
    	private void doParams(PreparedStatement ps, List<Object> params) {
    		if(ps != null &¶ms!= null&& params.size()>0) {
    			//循环注入
    			for(int i = 0;i<params.size();i++) {
    				try {
    					ps.setObject(i+1, params.get(i));
    				} catch (SQLException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    		
    	}
    	
    	//重载                                                                                                                      ...量词参数  代表任意个参数 本质是数组
    	private void doParams(PreparedStatement ps, Object...params) {
    		if(ps != null && params.length>0) {
    			//循环注入
    			for(int i = 0;i<params.length;i++) {
    				try {
    					ps.setObject(i+1, params[i]);
    				} catch (SQLException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}		
    	}
    	
    	public int doUpdate(String sql,Object... params) {
    		//定义返回值
    		int result = -1;
    		try {
    		//获取连接
    		Connection conn = getCon();
    		//创建预处理语句对象
    			PreparedStatement ps = conn.prepareStatement(sql);
    			//如果有问号,有参数,要注入参数
    			doParams(ps,params);
    			//执行
    			result = ps.executeUpdate();
    			//关闭各种连接,接口
    			closeAll(conn,null,ps);
    		} catch (SQLException e1) {
    			// TODO Auto-generated catch block
    			e1.printStackTrace();
    		}
    		//最终返回数据
    		return result;
    		
        }
    	
    	
          private void closeAll(Connection conn, ResultSet rs, PreparedStatement ps) {
        	  if(conn != null ) {
        		  try {
    				conn.close();
    			} catch (SQLException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
        	  }
        	  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();
    			}
        	  }
        	 }
    }

工具类(单例)(Oracle)

public class MyProperties extends Properties{
    	private static MyProperties myProperties;
    	
    	//构造函数私有化  单例模式
    	//单例  只有一个实例
    	private MyProperties(){					//装载				通过数据流获得的资源		配置文件
    		InputStream is = MyProperties.class.getClassLoader().getResourceAsStream("db.properties");
    		
    		//load 装载配置文件  void java.util.Properties.load(InputStream inStream) throws IOException
    		try {
    			this.load(is);
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    	
    	//单例模式设计之后 ,一定要有一个公有的方法,让其他对象访问到这个属性
    	public static MyProperties getInstance(){
    		if( myProperties  == null ){
    			myProperties = new MyProperties();
    		}
    		return myProperties;
    	}
    	
    }

db.properties

#db.properties
driverClass=oracle.jdbc.OracleDriver
url=jdbc:oracle:thin:@127.0.0.1:1521:orcl
user=scott
password=a

#mysql连接方式 #driverClass=com.mysql.jdbc.Driver #url=jdbc:mysql://127.0.0.1:3306/res #user=root #password=a

工具类(Mysql,DBHelper)

/**
     * 封装  数据库操作的工具类
     */
    public class DBHelper {
    	
    	//配置信息
    	//ORACLE
    	//private static String driverClassName = "oracle.jdbc.driver.OracleDriver";
    	//private String url = "jdbc:oracle:thin:@localhost:1521:ORCL";
    	//private String user = "scott";
    	//private String password = "a";
    	
    	//MySQL
    
    	//相关对象
    	private Connection conn = null;//连接对象
    	private PreparedStatement pstmt = null;//预编译
    	private ResultSet rs = null;//结果集
    			
    	//只在类中第一次加载才执行 且 执行一次      ->   当使用JNDI连接数据库时  可以注释该静态加载 
    	static {
    		//2、加载并注册依赖oracle.jdbc.driver.OracleDriver.class
    		try {
    			Class.forName( ReadConfig.getInstance().getProperty("driverClassName"));
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		}
    	}
    	
    	//建立连接
    	private Connection getConn() {
    		//3、建立连接     url  uname  pwd
    		//url 统一资源定位符   jdbc:oracle:thin:@数据库的IP地址:1521:实例名    127.0.0.1 | localhost:1521:ORCL 
    		//ctrl 1 + 2 -> L
    		try {
    			//conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ORCL", "scott", "a");
    			conn = DriverManager.getConnection(ReadConfig.getInstance().getProperty("url"), ReadConfig.getInstance());
    		
    			//从服务器 context.xml 中 上下文获取配置的DataSource  
    			//Context context= new InitialContext();
    			//从命名目录接口中根据资源名查询  前面 java:comp/env/blog 固定的   类似于协议
    			//DataSource dataSource =  (DataSource)context.lookup("java:comp/env/blog");
    			//从数据库连接池获取一个空闲的连接 
    			//conn = dataSource.getConnection();
    		/*} catch (NamingException e) {
    			e.printStackTrace();*/
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}
    		return conn;
    	}
    	
    	/**
    	 * 关闭资源
    	 * @param rs
    	 * @param pstmt
    	 * @param conn
    	 */
    	@SuppressWarnings("unused")
    	private void closeAll(ResultSet rs, PreparedStatement pstmt, Connection conn) {
    		//7、关闭资源  先开启的后关闭  后开启的先关闭  结果集 -> 语句块 -> 连接
    		if( rs != null) {
    			try {
    				rs.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    		if( pstmt != null) {
    			try {
    				pstmt.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    		if( conn != null) {
    			try {
    				conn.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    	
    	/**
    	 * 更新操作   Object ... params  不定参数   类似于数组  万物皆对象
    	 * @param sql  要执行的更新语句   可以 insert update delete 
    	 * @param params 要执行的SQL语句中的占位符? 所对应参数的值 
    	 * @return
    	 */
    	public int update(String sql, Object ... params) {
    		int result = -1;//定义默认的范围值
    		
    		try {
    			conn = this.getConn();//获取连接
    			pstmt = conn.prepareStatement(sql);//预编译对象装载SQL
    			this.setParams(pstmt, params);//需要给占位符注入参数
    			result = pstmt.executeUpdate();//执行更新语句
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}
    		return result;
    	}
    
    	/**
    	 * 给预编译语句块中占位符 赋值 设置参数
    	 * @param pstmt   预编译对象
    	 * @param params  要执行的SQL语句中的占位符? 所对应参数的值 
    	 */
    	private void setParams(PreparedStatement pstmt, Object ... params) {
    		//去空判断  说明没有参数给我   也就是执行的SQL语句中没有占位符
    		if( null == params || params.length <= 0) {
    			return;
    		}
    		//有参数 则循环参数  给预编译语句块中占位符 赋值
    		//先获取参数的长度  节省资源 提高性能
    		for(int i = 0, len = params.length; i < len; i++) {
    			//我不清楚占位符 对应的详细数据类型    万物皆对象
    			try {
    				pstmt.setObject( i + 1, params[i]);// % +v+ %
    			} catch (SQLException e) {
    				e.printStackTrace();
    				//项目可以使用日志来记录
    				System.out.println("第" + (i+1) + "个参数注值失败...");
    			}
    		}
    	}
    	
    	/**
    	 * 单条查询 返回一条记录   select * from userinfo where user_name = ? and user_pwd = ?
    	 * @param sql  查询SQL  
    	 * @param params 查询参数
    	 * @return map  一条记录
    	 */
    	public Map<String, Object> findSingle(String sql, Object ... params){
    		Map<String, Object> map = null;
    		try {
    			conn = this.getConn();//获取连接
    			pstmt = conn.prepareStatement(sql);//预编译对象装载SQL
    			this.setParams(pstmt, params);//需要给占位符注入参数
    			rs = pstmt.executeQuery();//执行更新语句
    			
    			//现获取所有的列名
    			List<String> columnNames = this.getAllColumnNames(rs);
    			if( rs.next()) { //处理结果集
    				map = new HashMap<String, Object>();
    				//map.put("user_id", rs.getInt("user_id"));
    				//map.put("user_name", rs.getString("user_name"));
    				//map.put("user_pwd", rs.getString("user_pwd"));
    				//如果换了查询的表  还会有这些列吗?  select * from emp; 
    				//如何查询表所对应各个列的名称?  请去API 先行查看 rs.getMetaData()
    				
    				Object value = null;//列所对应的值
    				String type = "";//列所对应的值的类型
    				
    				//增强for
    				for(String columnName : columnNames) {
    					//列对应的类型不确定
    					//map.put(columnName, rs.getObject(columnName));
    					value = rs.getObject(columnName);
    					//判空
    					if( null == value) {
    						map.put(columnName, value);
    						continue;
    					}
    					type = value.getClass().getName(); //获取类型
    					//System.out.println(type); //oracle.sql.BLOB   java.math.BigDecimal
    					//判断类型
    					//TODO 如果是Blob类型 该怎么办 ?  图片的处理??? 想办法获取对应的数据类型?
    					if("oracle.sql.BLOB".equals(type)) {
    						//获取对应类型数据
    						Blob blob = rs.getBlob(columnName);
    						//获取对应二进制流操作
    						try(InputStream is = blob.getBinaryStream()){
    							byte [] bt = new byte[ (int)blob.length()];
    							is.read(bt);
    							map.put(columnName, bt);//存入字节数组
    						}catch(IOException e) {
    							e.printStackTrace();
    						}
    					}else {
    						map.put(columnName, value);
    					}
    				}
    			}
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}
    		return map;
    	}
    	
    	/**
    	 * JDBC2.0 获取所有的列名
    	 * @param rs
    	 * @return
    	 */
    	public List<String> getAllColumnNames(ResultSet rs){
    		//存储列的集合
    		List<String> list = new ArrayList<String>();
    		try {
    			//getMetaData() 获取此 ResultSet 对象的列的编号、类型和属性
    			ResultSetMetaData rsmd = rs.getMetaData();
    			//获取列的数量
    			int count = rsmd.getColumnCount();
    			//列的范围确定 循环
    			for(int i = 1; i <= count; i++){
    				//获取对应列的列名
    				list.add(rsmd.getColumnName(i).toLowerCase());
    			}
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}
    		return list;
    	}
    	
    	/**
    	 * 多行查询 返回多条  select * from emp; 
    	 * @param sql  查询SQL  
    	 * @param params 查询参数
    	 * @return list 
    	 */
    	public List<Map<String, Object>> findMultiple(String sql, Object ... params){
    		List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
    		Map<String, Object> map = null;
    		try {
    			conn = this.getConn();//获取连接
    			pstmt = conn.prepareStatement(sql);//预编译对象装载SQL
    			this.setParams(pstmt, params);//需要给占位符注入参数
    			rs = pstmt.executeQuery();//执行更新语句
    			
    			//现获取所有的列名
    			List<String> columnNames = this.getAllColumnNames(rs);
    			
    			while( rs.next()) { //处理结果集
    				map = new HashMap<String, Object>();
    				Object value = null;//列所对应的值
    				String type = "";//列所对应的值的类型
    				
    				//增强for
    				for(String columnName : columnNames) {
    					//列对应的类型不确定
    					//map.put(columnName, rs.getObject(columnName));
    					value = rs.getObject(columnName);
    					//判空
    					if( null == value) {
    						map.put(columnName, value);
    						continue;
    					}
    					type = value.getClass().getName(); //获取类型
    					//System.out.println(type); //oracle.sql.BLOB   java.math.BigDecimal
    					//判断类型
    					//TODO 如果是Blob类型 该怎么办 ?  图片的处理??? 想办法获取对应的数据类型?
    					if("oracle.sql.BLOB".equals(type)) {
    						//获取对应类型数据
    						Blob blob = rs.getBlob(columnName);
    						//获取对应二进制流操作
    						try(InputStream is = blob.getBinaryStream()){
    							byte [] bt = new byte[ (int)blob.length()];
    							is.read(bt);
    							map.put(columnName, bt);//存入字节数组
    						}catch(IOException e) {
    							e.printStackTrace();
    						}
    					}else {
    						map.put(columnName, value);
    					}
    				}
    				list.add(map);
    			}
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}
    		return list;
    	}
    	
    	/**
    	 *  以对象的方式 将将查询结果返回
    	 *   c.newInstance() -> new AdminInfo() 
    	 *   m.invoke(obj, value)  激活m方法
    	 *   获取当前class实例中所有的方法和属性
    	 * @param c		
    	 * @param <T> 限定类型
    	 * @param sql  查询SQL 
    	 * @param params 注入的参数 
    	 * @return
    	 */
    	public <T>List<T> findMultiple(Class c,String sql, Object ... params){
    		List<T> list = new ArrayList<T>();
    		System.out.println(1111);
    		try {
    			conn = this.getConn();//获取连接
    			pstmt = conn.prepareStatement(sql);//预编译对象装载SQL
    			this.setParams(pstmt, params);//需要给占位符注入参数
    			rs = pstmt.executeQuery();//执行更新语句
    			
    			//现获取所有的列名
    			List<String> columnNames = this.getAllColumnNames(rs);
    			
    			T t = null;//声明一个对象
    			Object value = null;//列所对应的值
    			String typeName = "";//列所对应的值的类型
    			
    			//通过反射来获取类中所有的方法 methods
    			Method [] methods = c.getDeclaredMethods();
    			
    			while( rs.next()) { //处理结果集
    				//创建对象
    				t =  (T)c.newInstance();//调用无参数的构造方法  AdminInfo admin = new AdminInfo();
    				
    				//增强for  列
    				for(String columnName : columnNames) {
    					//列对应的类型不确定
    					value = rs.getObject(columnName);
    					
    					//判空
    					if( null == value) { // 数据库无数据
    						continue;
    					}
    					
    					//循环类中所有的方法
    					for(Method method : methods) {
    						//是否有对应setXXX 方法名   set + columnName -> method的名字
    						String name = "set" + columnName;
    						//获取列对应值的类型
    						typeName = value.getClass().getName();
    						//System.out.println( typeName );
    						//找到对应的方法名
    						if( name.equalsIgnoreCase( method.getName())) {
    							//判断数据类型
    							if("java.math.BigDecimal".equals(typeName)) {
    								try {
    									method.invoke( t, rs.getDouble( columnName ));
    								}catch(Exception e) {
    									method.invoke( t, rs.getString( columnName ));
    								}
    							}else if("java.lang.String".equals(typeName)) {
    								method.invoke( t, rs.getString( columnName ));
    							}else if("java.lang.Double".equals(typeName)) {
    								method.invoke( t, rs.getDouble( columnName ));
    							}else if("java.lang.Integer".equals(typeName)) {
    								method.invoke( t, rs.getInt( columnName ));
    							}else if("java.lang.Date".equals(typeName)) {
    								//MySQL 中date 数据类型 转换成JavaBean 对象中使用String 
    								method.invoke( t, rs.getString( columnName ));
    							}else if("oracle.sql.BLOB".equals(typeName)) {  //TODO 如果是Blob类型 该怎么办 ?  图片的处理??? 想办法获取对应的数据类型?
    								//获取对应类型数据
    								Blob blob = rs.getBlob(columnName);
    								//获取对应二进制流操作
    								try(InputStream is = blob.getBinaryStream()){
    									byte [] bt = new byte[ (int)blob.length()];
    									is.read(bt);
    									method.invoke( t, bt);
    								}catch(IOException e) {
    									e.printStackTrace();
    								}
    							}else if("oracle.sql.CLOB".equals(typeName)){
    								Reader in = rs.getCharacterStream(columnName);
    								BufferedReader br = new BufferedReader( in );
    								StringBuffer sb =  new StringBuffer();
    								try {
    									String str = br.readLine();//每次读取一行数据
    									while( null != str ) {
    										sb.append( str );
    										str = br.readLine();
    									}
    									method.invoke( t, sb.toString());
    								} catch (IOException e) {
    									e.printStackTrace();
    								}
    							}else {
    								//TODO 后期需要 自行扩展
    							}
    						}
    					}
    				}
    				list.add(t); //设置对象到list集合中
    			}
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
    			e.printStackTrace();
    		}
    		return list;
    	}
    	
    	/**
    	 *  以对象的方式 将将查询结果返回
    	 *   c.newInstance() -> new AdminInfo() 
    	 *   m.invoke(obj, value)  激活m方法
    	 *   获取当前class实例中所有的方法和属性
    	 * @param c		
    	 * @param <T> 限定类型
    	 * @param sql  查询SQL 
    	 * @param params 注入的参数 
    	 * @return 
    	 * @return
    	 */
    	public <T> T findSingle(Class c,String sql, Object ... params){
    		T t = null;//声明一个对象
    		try {
    			conn = this.getConn();//获取连接
    			pstmt = conn.prepareStatement(sql);//预编译对象装载SQL
    			this.setParams(pstmt, params);//需要给占位符注入参数
    			rs = pstmt.executeQuery();//执行更新语句
    			
    			//现获取所有的列名
    			List<String> columnNames = this.getAllColumnNames(rs);
    			
    			Object value = null;//列所对应的值
    			String typeName = "";//列所对应的值的类型
    			
    			//通过反射来获取类中所有的方法 methods
    			Method [] methods = c.getDeclaredMethods();
    			
    			if( rs.next()) { //处理结果集
    				//创建对象
    				t =  (T)c.newInstance();//调用无参数的构造方法  AdminInfo admin = new AdminInfo();
    				//增强for  列
    				for(String columnName : columnNames) {
    					//列对应的类型不确定
    					value = rs.getObject(columnName);
    					//判空
    					if( null == value) { // 数据库无数据
    						continue;
    					}
    					//循环类中所有的方法
    					for(Method method : methods) {
    						
    						//是否有对应setXXX 方法名   set + columnName -> method的名字
    						String name = "set" + columnName;
    						//获取列对应值的类型
    						typeName = value.getClass().getName();
    						//System.out.println( name + "--" + typeName );
    						//找到对应的方法名
    						if( name.equalsIgnoreCase( method.getName())) {
    							//判断数据类型
    							if("java.math.BigDecimal".equals(typeName)) {
    								try {
    									method.invoke( t, rs.getDouble( columnName ));
    								}catch(Exception e) {
    									method.invoke( t, rs.getString( columnName ));
    								}
    							}else if("java.lang.String".equals(typeName)) {
    								method.invoke( t, rs.getString( columnName ));
    							}else if("java.lang.Double".equals(typeName)) {
    								method.invoke( t, rs.getDouble( columnName ));
    							}else if("java.lang.Integer".equals(typeName)) {
    								method.invoke( t, rs.getInt( columnName ));
    							}else if("java.lang.Date".equals(typeName)) {
    								//MySQL 中date 数据类型 转换成JavaBean 对象中使用String 
    								method.invoke( t, rs.getString( columnName ));
    							}else if("oracle.sql.BLOB".equals(typeName)) {  //TODO 如果是Blob类型 该怎么办 ?  图片的处理??? 想办法获取对应的数据类型?
    								//获取对应类型数据
    								Blob blob = rs.getBlob(columnName);
    								//获取对应二进制流操作
    								try(InputStream is = blob.getBinaryStream()){
    									byte [] bt = new byte[ (int)blob.length()];
    									is.read(bt);
    									method.invoke( t, bt);
    								}catch(IOException e) {
    									e.printStackTrace();
    								}
    							}else if("oracle.sql.CLOB".equals(typeName)){
    								Reader in = rs.getCharacterStream(columnName);
    								BufferedReader br = new BufferedReader( in );
    								StringBuffer sb =  new StringBuffer();
    								try {
    									String str = br.readLine();//每次读取一行数据
    									while( null != str ) {
    										sb.append( str );
    										str = br.readLine();
    									}
    									method.invoke( t, sb.toString());
    								} catch (IOException e) {
    									e.printStackTrace();
    								}
    							}else {
    								//TODO 后期需要 自行扩展
    							}
    						}
    					}
    				}
    			}
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
    			e.printStackTrace();
    		}
    		return t;
    	}
    	   public int total(String sql,Object...params) {
    		int result = 0;
    		try {
    			conn = this.getConn();
    			pstmt = conn.prepareStatement(sql);
    			//设置参数
    			setParams(pstmt,params);
    			//执行语句块
    			rs= pstmt.executeQuery();
    			
    			//处理结果集
    			if(rs.next()) {
    				result = rs.getInt(1);//列索引第一列
    			}
    		} catch (SQLException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally {
    			this.closeAll(rs, pstmt, conn);
    		}
    		return result;
    	}
    }

工具类(mysql,也是单例)

public class ReadConfig extends Properties{
    	private static final long serialVersionUID = 1560020482133144083L;
    	//饿汉单例   提前实例化对�?
    	private static ReadConfig instance = new ReadConfig();
    
    	//构造方法私有化  
    	private ReadConfig() {
    		//想办法读取自己的配置文件   
    		//JDK1.7 会自动关闭且�?定关闭资�?   try - with -resources
    		try(InputStream is = this.getClass().getClassLoader().getResourceAsStream("db.properties")){
    			//业务代码  流处�? 
    			this.load(is); //读取配置文件
    		}catch(IOException e) {
    			e.printStackTrace();
    		}
    	}
    	//因为构�?�私有化就意味着外部无法实例化该对象 必须对外提供�?个获取实例的方法  并在内部提前实例�? 
    	//又因为外部无法是实例�? 只能通过类名方法 该方�? �?声明为静态的 
    	public  static ReadConfig getInstance() {
    		return instance;
    	}
    }

db.properties

#MySQL5
#driverClassName=com.mysql.jdbc.Driver
#url=jdbc:mysql://localhost:3306/blog
#user=root
#password=a

#MySQL8 driverClassName=com.mysql.cj.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/数据库名?useOldAliasMetadataBehavior=true&useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8 user=root password=a #Oracle #driverClassName=oracle.jdbc.driver.OracleDriver #url=jdbc:oracle:thin:@localhost:1521:orcl #user=scott #password=a

SQL注入

public class AdminInfoDAOImpl implements IAdminInfoDAO {
    
    	@Override
    	public AdminInfo login(String aname, String pwd) {
             DBHelper db = new DBHelper();
             String sql = "select * from admininfo where aname = ? and pwd = md5(?)";
             return db.findSingle(AdminInfo.class,sql,aname,pwd);
    	}
    
    	@Override
    	public int add(String aname, String pwd, String photo) {
    		DBHelper db = new DBHelper();
            String sql = "insert into admininfo value(0,?,md5(?),?)";
            return db.update(sql, aname,pwd,photo);
    	}
    
    	//默认不查询密码 如果需要查询 将来界面渲染密码  必须摘码显示 123456 -> 1***6
    	@Override
    	public List<AdminInfo> findAll() {
    		DBHelper db = new DBHelper();
            String sql = "select aid,aname,photo from admininfo order by aid desc";
            return db.findMultiple(AdminInfo.class, sql);
    	}
    }

== sql注入漏洞也就是sql拼接==

PreparedStatement:可以预防SQL注入,我们使用?来代替具体的字段,避免直接在sql语句中添加值,从而预防sql注入。
比如之前使用
String sql = "select * from admininfo where aname = “+ aname + " and pwd = md5(” + pwd+ “)”;
现在我们可以直接使用:
String sql = “select * from admininfo where aname = ? and pwd = md5(?)”;

上述我们使用的工具类就是使用PreparedStatement来的。