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();
}
}
步骤总结:
- 加载驱动
- 连接数据库DriverManager
- 获取执行sql的对象Statement
- 返回获得的结果集(list)
- 释放连接
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来的。