赞
踩
操作数据库常用的执行方法:
execute()可以进行增删改查
executeUpdate() 可以执行增删改 但是不能执行查询
exeuctQuery():只可以执行查询
我们在封装这个工具类的时候,只需要封装两种:一种用来执行增删改操作,一种用来执行查询操作。
一般我们会将数据库中的表封装成一个类,那么表中的一条记录就对应这一个对象,字段就是类的属性。
因此一般我们也将与数据库直接交互的这一层代码称之为DAO层(Database access Object)
反射和泛型:
泛型:参数化类型 用在类上 方法上 接口上
反射:通过Class对象获得类中的属性,方法 ,构造方法
可以通过反射来创建对象,调用方法 ,访问属性或者为属性赋值
// 增删改查的工具类 public class CRUDTemplate { /** * 增删改操作 * @param sql sql语句 * @param params sql语句中的参数 * @return */ public static int executeUpdate(String sql,Object ... params){ Connection conn = null; PreparedStatement pstmt = null; int rows = 0; try { // 获取连接 conn = JDBCUtil.getConnection(); //获取sql语句的预编译对象 pstmt = conn.prepareStatement(sql); //给占位符赋值 for (int i= 0 ;i <params.length;i++){ pstmt.setObject(i +1,params[i]); } // 执行sql rows = pstmt.executeUpdate(); } catch (SQLException e) { throw new RuntimeException(e); }finally { JDBCUtil.releaseSource(null,pstmt,conn); } return rows; } /** * 查询操作 * @param sql * @param handler * @param params * @return * @param <T> */ public static <T> T executQuery(String sql,IResultSetHandler<T> handler, Object ... params){ Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try{ conn = JDBCUtil.getConnection(); pstmt = conn.prepareStatement(sql); for(int i = 0 ; i < params.length;i++){ pstmt.setObject(0 + 1,params[i]); } //执行sql 返回结果集 rs = pstmt.executeQuery(); //调用专门的结果集处理接口来处理结果集 至于返回的是什么类型的结果 有结果集处理器决定 return handler.handle(rs); } catch (SQLException e) { throw new RuntimeException(e); }finally { JDBCUtil.releaseSource(rs,pstmt,conn); } } }
这是一个数据库操作工具类,提供了增删改查的方法,其中:
executeUpdate()方法用于执行增删改操作,接收一个SQL语句和参数列表,返回受
影响的行数。
executQuery()方法用于执行查询操作,接收一个SQL语句、一个结果集处理器和参
数列表,返回处理后的结果。
该工具类中使用了JDBCUtil类提供的getConnection()和releaseSource()方法获取
和释放数据库连接。
该工具类中还使用了一个IResultSetHandler接口,用于处理查询结果集并返回指定
类型的结果。
//返回单个对象 public class BeanHandler<T> implements IResultSetHandler<T>{ private Class<T> clazz; public BeanHandler(Class<T> clazz){ this.clazz = clazz; } @Override public List<T> handle(ResultSet rs) throws SQLException, InstantiationException, IllegalAccessException, IntrospectionException, InvocationTargetException { List<T> list = new ArrayList<>(); if (rs.next()){ T obj = clazz.newInstance();//创建一个实例对象 // 获取字节码信息 拿到该类的属性 方法 等信息封装成BeanInfo BeanInfo beanInfo = Introspector.getBeanInfo(clazz, Object.class); // 获取所有的属性信息 获取所有的属性名称 PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors(); for (PropertyDescriptor pd : pds){// 对每一个属性 依次读取数据库中的字段对应的值 并进行赋值操作 // 获取字段名称 将来在创建实体类的时候 要求属性名必须和字段名一致 Object o = rs.getObject(pd.getName()); //执行当前方法并传入参数 pd.getWriteMethod().invoke(obj,o); } list.add(obj); if (list.size()>0) return list; } return null; } }
public class BeanListHandler<T> implements IResultSetHandler<T>{ private Class<T> clazz; public BeanListHandler(Class<T> clazz){ this.clazz = clazz; } @Override public List<T> handle(ResultSet rs) throws SQLException, InstantiationException, IllegalAccessException, IntrospectionException, InvocationTargetException { // 获取字节码信息 BeanInfo beanInfo = Introspector.getBeanInfo(clazz, Object.class); // 获取指定的属性信息 PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors(); List<T> list = new ArrayList<>(); while(rs.next()){ T obj = clazz.newInstance(); for (PropertyDescriptor pd :pds){ // 获取字段名=属性名 Object o = rs.getObject(pd.getName()); pd.getWriteMethod().invoke(obj,o); } list.add(obj); } return list; } }
//把jdbc返回的结果集封装成特定类型 public interface IResultSetHandler<T> { //专门用来处理结果集 // T handle(ResultSet rs) throws SQLException, InstantiationException, IllegalAccessException, IntrospectionException, InvocationTargetException; List<T> handle(ResultSet rs) throws SQLException, InstantiationException, IllegalAccessException, IntrospectionException, InvocationTargetException;; } public class CRUDTemplateTest { public static void main(String[] args) { String sql = "select * from users "; List<User> users = CRUDTemplate.executQuery(sql,new BeanListHandler<User> (User. class)); System.out.println(users.size()); } }
//返回单个对象 public class BeanHandler<T> implements IResultSetHandler<T>{ private Class<T> clazz; public BeanHandler(Class<T> clazz){ this.clazz = clazz; } @Override public T handle(ResultSet rs) throws SQLException, InstantiationException, IllegalAccessException, IntrospectionException, InvocationTargetException { if (rs.next()){ T obj = clazz.newInstance();//创建一个实例对象 // 获取字节码信息 拿到该类的属性 方法 等信息封装成BeanInfo BeanInfo beanInfo = Introspector.getBeanInfo(clazz, Object.class); // 获取所有的属性信息 获取所有的属性名称 PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors(); for (PropertyDescriptor pd : pds){// 对每一个属性 依次读取数据库中的字段对应的值 并进行赋值操作 // 获取字段名称 将来在创建实体类的时候 要求属性名必须和字段名一致 Object o = rs.getObject(pd.getName()); //执行当前方法并传入参数 pd.getWriteMethod().invoke(obj,o); } return obj; } return null; } }
public class BeanListHandler<T> implements IResultSetHandler<List<T>>{ private Class<T> clazz; public BeanListHandler(Class<T> clazz){ this.clazz = clazz; } @Override public List<T> handle(ResultSet rs) throws SQLException, InstantiationException, IllegalAccessException, IntrospectionException, InvocationTargetException { // 获取字节码信息 BeanInfo beanInfo = Introspector.getBeanInfo(clazz, Object.class); // 获取指定的属性信息 PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors(); List<T> list = new ArrayList<>(); while(rs.next()){ T obj = clazz.newInstance(); for (PropertyDescriptor pd :pds){ // 获取字段名=属性名 Object o = rs.getObject(pd.getName()); pd.getWriteMethod().invoke(obj,o); } list.add(obj); } return list; } }
DButils是一个为做一些准备如关闭连接,装载驱动 获得连接 提交事务 回滚事务 所有的方法都是静
态的
QueryRunner 简化了sql查询,CRUD
ResultSetHandler 接口 结果集的处理接口
public class DBUtilsTest { @Test public void insertData() throws SQLException { Connection conn = JDBCUtil.getConnection(); //创建sql执行工具 QueryRunner qr = new QueryRunner(); String sql = "insert into tb_user(name,age,status,gender)values(?,?,?,?)"; int rows = qr.update(conn,sql,"张三",22,1,"男"); System.out.println(rows); DbUtils.closeQuietly(conn); } @Test public void updateData() throws SQLException { Connection conn = JDBCUtil.getConnection(); //创建sql执行工具 QueryRunner qr = new QueryRunner(); String sql = "update tb_user set name =? where id=?"; int rows = qr.update(conn,sql,"李四",4); System.out.println(rows); DbUtils.closeQuietly(conn); } @Test public void deleteData() throws SQLException { Connection conn = JDBCUtil.getConnection(); //创建sql执行工具 QueryRunner qr = new QueryRunner(); String sql = "delete from tb_user where id=?"; int rows = qr.update(conn,sql,4); System.out.println(rows); DbUtils.closeQuietly(conn); } @Test public void selectOneData() throws SQLException { Connection conn = JDBCUtil.getConnection(); //创建sql执行工具 QueryRunner qr = new QueryRunner(); String sql = "select * from tb_user where id=?"; User user = qr.query(conn,sql, new BeanHandler<>(User.class),1); System.out.println(user); DbUtils.closeQuietly(conn); } @Test public void selectAllData() throws SQLException { Connection conn = JDBCUtil.getConnection(); //创建sql执行工具 QueryRunner qr = new QueryRunner(); String sql = "select * from tb_user "; List<User> users = qr.query(conn,sql, new BeanListHandler<>(User.class)); System.out.println(users); DbUtils.closeQuietly(conn); } }
/** * 数据访问层 */ public class BankDao { /** * 加钱的方法 * @param account 被转账的账户 * @param money 转账的金额 * @return */ public int addMoney(Connection conn,String account, int money) throws SQLException { String sql = "update account set money = money+? where aname=?"; QueryRunner qr = new QueryRunner(); int rows = qr.update(conn,sql,account,money); return rows; } /** * 减钱的方法 * @param account 转账的账户 * @param money 转账的金额 * @return */ public int subMoney(Connection conn,String account,int money) throws SQLException { String sql = "update account set money = money-? where aname=?"; QueryRunner qr = new QueryRunner(); int rows = qr.update(conn,sql,money,account); return rows; } }
/** * 业务类 实现转账操作 */ public class BankService { private BankDao dao = new BankDao(); public void transfer(String addAccount,String subAccount,double money){ Connection conn = JDBCUtil.getConnection(); // 开启事务(关闭自动提交) try { conn.setAutoCommit(false); int i = dao.addMoney(conn,addAccount,money); System.out.println(i); System.out.println(10/0); int a = dao.subMoney(conn,subAccount,money); System.out.println(a); DbUtils.commitAndClose(conn); } catch (SQLException e) { DbUtils.rollbackAndCloseQuietly(conn); } } }
在查询的时候,给字段起别名 这样就可以结局不一致的问题。但是别名应该和属性名一致
@Test
public void selectOneData() throws SQLException {
Connection conn = JDBCUtil.getConnection();
//创建sql执行工具
QueryRunner qr = new QueryRunner();
String sql = "select id, name username,age userAge,status,gender from
tb_user where id=?";
User user = qr.query(conn,sql, new BeanHandler<>(User.class),1);
System.out.println(user);
DbUtils.closeQuietly(conn);
}
当使用dbutils进行查询的时候,要么实体的属性名和字段名一致,要么给字段起别名 ,别名和属性名一致。
如果数据库中的字段名由多个单词组成,中间以下划线分隔。此时属性名应该遵循小驼峰命名法进行命名,
在查询数据看的时候,使用别名解决
网址
常用的数据库连接池:DBCP、C3p0 国货之光 druid
JDBC的数据库连接池使用javax.sql.DataSource接口进行规范。
通过硬编码的方式 得到连接池对象 从中获得连接
public class DruidTest {
@Test
public void druidTest() throws SQLException {
DruidDataSource dds = new DruidDataSource();
dds.setDriverClassName("com.mysql.cj.jdbc.Driver");
dds.setUrl("jdbc:mysql://localhost:3306/studydb");
dds.setUsername("root");
dds.setPassword("root");
// 获取连接
Connection conn = dds.getConnection();
System.out.println(conn);
conn.close();//释放连接 释放连接池
}
}
通过外部配置:
//通过配置文件的方式得到Datasources
@Test
public void druidTest1() throws Exception {
Properties prop = new Properties();
InputStream in =
DruidTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
prop.load(in);
DataSource ds = DruidDataSourceFactory.createDataSource(prop);
System.out.println(ds.getConnection());
}
其他配置
driverClassName = com.mysql.cj.jdbc.Driver
url= jdbc:mysql://localhost:3306/studydb
username=root
password=root
#初始化连接数
initialSize=1
# 最小的空闲的连接数
minIdle=2
#最大的连接数
maxActive =5
常见的加密方式:Base64加密算法,MD5加密,对称加密算 ,非对称加密算法,数字签名算法,数字整
数,CA认真等。
加密方式的使用场景:
基本的加密算法的底层原理
public class MD5Test { public static void main(String[] args) { String str = "123456"; // 生成普通的MD5的密码 MessageDigest md5 = null; try { //创建加密对象 同时指定加密算法为md5 md5 = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } char[] charArray = str.toCharArray(); byte[] byteArray = new byte[charArray.length]; for (int i = 0; i < charArray.length; i++) { byteArray[i] = (byte) charArray[i]; } byte[] md5Bytes = md5.digest(byteArray); StringBuffer hexValue = new StringBuffer(); for (int j = 0; j < md5Bytes.length; j++) { int val = (int) md5Bytes[j] & 0xff; if (val < 16) { hexValue.append("0"); } else { hexValue.append(Integer.toHexString(val)); } } System.out.println(hexValue.toString()); } }
使用工具类
Apache Commons Codec 1.15
public static void main(String[] args) {
String encode = DigestUtils.md5Hex("abc123456");
System.out.println(encode);
}
}
加严加密:
public static void main(String[] args) {
//普通加密
String encode = DigestUtils.md5Hex("abc123456");
System.out.println(encode);
//加盐加密
String encode2 = Md5Crypt.apr1Crypt("abc123456","sxjzit");
System.out.println(encode2);
}
密码的校验:
MD5加密是不可逆的,在校验的时候 应该是对用户输入的密码在此加密,并且应该使用相同的盐。这样才能
保证两次加密的密文字符串相同。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。