JDBC(2)JAVA连接数据库之 分页操作、事务操作、代理模式
来源:互联网 发布:gossip协议《算法》 编辑:程序博客网 时间:2024/06/04 00:27
分页操作(排序)
与表相对应的用户类
package lesson2;public class User { private int id; private String username; private String userpass; private String email; public User (){} public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getUserpass() { return userpass; } public void setUserpass(String userpass) { this.userpass = userpass; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public User(int id, String username, String userpass, String email) { super(); this.id = id; this.username = username; this.userpass = userpass; this.email = email; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", userpass=" + userpass + ", email=" + email + "]"; }}
与表相关操作的包装类(UserDao)
package lesson2;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.util.ArrayList;import java.util.List;/** * 分页操作 * @author hh * */public class UserDao { public List<User> findByPage(int page,int pageSize){ Connection con = null; PreparedStatement pstmt = null; ResultSet rs = null; List<User> users = new ArrayList<User>(); try { con = JdbcUitl.getConn(); int begin=(page-1)*pageSize+1; int end = page*pageSize; String sql="select id,username,userpass,email from" + "(select id,username,userpass,email,rownum rn from bb_user order by id)" + "where rn between ? and ?"; pstmt = con.prepareStatement(sql); pstmt.setInt(1, begin); pstmt.setInt(2, end); rs=pstmt.executeQuery(); while(rs.next()){ User user = new User(); user.setId(rs.getInt("id")); user.setUsername(rs.getString("username")); user.setUserpass(rs.getString("userpass")); user.setEmail(rs.getString("email")); users.add(user); } } catch (Exception e) { e.printStackTrace(); }finally{ JdbcUitl.close(pstmt, rs); } return users; }}
测试类
package lesson2;import java.util.ArrayList;import java.util.List;public class JdbcDemo1 { public static void main(String[] args) { UserDao ud = new UserDao(); List<User> users =ud.findByPage(1,5); for (User user : users) { System.out.println(user); } }}
事务
- 创建一张表
- 把表相关的操作封装
- 只有提交事务之后,jabc才能操作数据
- commit 提交 rollback 回滚
- Connection 对象默认操作完后提交事务。
- 如果不要自动提交,需要操作:con.setAutoCommit(false);
创建新的测试表格account 创建与之对应的数据类
package lesson2;public class Account { private int id; private int money; private String name; public Account(){} public Account(int id, int money, String name) { super(); this.id = id; this.money = money; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Account [id=" + id + ", money=" + money + ", name=" + name + "]"; }}
与表相关操作的包装类(AccountDao)
这可以看到没有关闭Connection对象,是为了后面的事务操作
package lesson2;import java.nio.Buffer;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.PseudoColumnUsage;import java.sql.ResultSet;import java.util.ArrayList;import java.util.List;import oracle.net.aso.p;public class AccountDao { public int addAccount(Account account){ Connection con = null; PreparedStatement pstmt = null; int n = 0; try { con = JdbcUitl.getConn(); pstmt = con.prepareStatement("insert into account(id,money,name)values(?,?,?)"); pstmt.setInt(1, account.getId()); pstmt.setInt(2, account.getMoney()); pstmt.setString(3, account.getName()); n=pstmt.executeUpdate(); } catch (Exception e) { e.printStackTrace(); }finally{ JdbcUitl.close(pstmt, null); } return n; } public Account findById(int id){ Connection con = null; PreparedStatement pstmt = null; ResultSet rs = null; Account account = null; try { con = JdbcUitl.getConn(); pstmt=con.prepareStatement("select * from account where id="+id); rs = pstmt.executeQuery(); if(rs.next()){ account = new Account(); account.setId(rs.getInt("id")); account.setMoney(rs.getInt("money")); account.setName(rs.getString("name")); } } catch (Exception e) { e.printStackTrace(); }finally{ JdbcUitl.close(pstmt, rs); } return account; } public List<Account> getllAccount(){ Connection con = null; PreparedStatement pstmt = null; ResultSet rs = null; List<Account> accounts = new ArrayList<Account>(); try { con = JdbcUitl.getConn(); pstmt = con.prepareStatement("select id,money,name from account"); rs = pstmt.executeQuery(); while(rs.next()){ Account account = new Account(); account.setId(rs.getInt("id")); account.setMoney(rs.getInt("money")); account.setName(rs.getString("name")); accounts.add(account); } } catch (Exception e) { e.printStackTrace(); }finally{ JdbcUitl.close(pstmt, rs); } return accounts; } public int updateAccount(int id,int money){ Connection con = null; PreparedStatement pstmt = null; int n = 0; try { con = JdbcUitl.getConn(); String sql = "update account set money = ? where id=?"; pstmt = con.prepareStatement(sql); pstmt.setInt(1, money); pstmt.setInt(2, id); n=pstmt.executeUpdate(); } catch (Exception e) { e.printStackTrace(); }finally{ JdbcUitl.close(pstmt,null); } return n; }}
测试类
package lesson2;import java.util.List;public class JdbcDemo2 { public static void main(String[] args) { AccountDao ad = new AccountDao(); //查询全部记录/* List<Account> accounts = ad.getllAccount(); for (Account account : accounts) { System.out.println(account); } */ //修改记录/* int n = ad.updateAccount(1002, 300); System.out.println(n); */ //根据主键查询 Account account = ad.findById(1001); System.out.println(account); }}
- 数据层:关于数据库的操作 ,增删改查
- 业务层:正常的业务处理 比如转账业务(A—>B):修改两次数据操作。也有可能和数据层无关
- 完成转账操作
- A转账给B 这个过程A减少钱,若果B出意外了。所以两个操作放在一个事物中,而connection中,默认自动提交。
- 要在同一个事物中操作,就必须多个关于数据的操作必须是同一个连接,要保证同一个线程中是同一个connection。
- 修改 JdbcUtil threadLocal
- Connection 的关闭,必须在一个业务操作完成之后,进行关闭。
- 业务处理开始之前,开启事物,业务处理之后提交事物,业务处理有异常 回滚事物,左后关闭connection
- 将来会有,一个业务操作一组dao, 我们就是需要把多个业务包装到一个dao中,要么全成功,要么全全失败、
- 但是每个业务都这样写,比较繁琐。我们希望利用代理的方式。
JdbcUitl类
保证同一个线程中是同一个connection。方面后面的事务操作
package lesson2;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.Properties;public class JdbcUitl { private static Properties prop = new Properties(); private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); static{ try { prop.load(JdbcUitl.class.getResourceAsStream("/database.properties")); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConn(){ //保证同一个线程中是同一个connection Connection con = tl.get(); try { if(con==null){ Class.forName(prop.getProperty("driverClass")); con = DriverManager.getConnection( prop.getProperty("url"),prop.getProperty("user"),prop.getProperty("pass")); tl.set(con); } return tl.get(); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 资源关闭 * @param con * @param stmt * @param rs */ public static void close(Statement stmt,ResultSet rs){ if(rs!=null) try { rs.close(); } catch (Exception e) { e.printStackTrace(); } if(stmt!=null) try { stmt.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void closeConnection(){ Connection con = tl.get(); if(con!=null){ try { con.close(); tl.remove(); } catch (Exception e) { e.printStackTrace(); } } }}
业务类
手动抛出异常,测试可以发现,用之前的操作方法,如果两个操作之间发生异常,则会造成数据不一致。
package lesson2;import java.sql.Connection;import java.sql.JDBCType;import java.sql.SQLException;public class AccountService { private boolean flag; public void setFlag(boolean flag) { this.flag = flag; } AccountDao ad = new AccountDao(); //未来用别的模式初始化(工厂模式) /** * 增加账户的业务 * @param account */ public void addAccount(Account account){ //如果有密码:需要加密 然后增加一条记录 } /** * 转账业务 * @param id1 * @param id2 * @param money */ public void changeAccount(int id1,int id2,int money){ Connection con = null; try { con = JdbcUitl.getConn(); //开启事务,关闭自动提交 con.setAutoCommit(false); Account account1 = ad.findById(id1); Account account2 = ad.findById(id2); int n1=ad.updateAccount(id1,account1.getMoney()-money); if(flag) throw new RuntimeException("可能出现某种异常"); int n2=ad.updateAccount(id2,account2.getMoney()+ money); //提交事务 con.commit(); } catch (Exception e) { e.printStackTrace(); try { //回滚事务 con.rollback(); } catch (SQLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } }finally{ //关闭事务 JdbcUitl.closeConnection(); } }}
测试类
package lesson2;/** * 事物测试类 * @author hh * */public class JdbcDemo3 { public static void main(String[] args) { AccountService service = new AccountService(); service.setFlag(true); service.changeAccount(1001, 1002, 100); }}
代理模式
- 代理模式(基于接口编程,业务要写成接口。所有操作,无论DAO还是业务都应该写成接口)。面向方面的编程aop。关心业务的人员只关心业务,关心事物的人员只关心事物。
- 静态代理
- 创建一个代理类,和被代理类实现用一个接口,并且把被代理类的实例作为自己的成员。
- 静态代理本身也是一种架构模式
- 缺陷:要做的辅助操作(实务,日志)在每个业务方法中都要进行重写。
- 动态代理
- 动态代理处理器 实现InvokeHandler接口
- 把目标对象作为成员(要生成代理的对象)
- 重写invoke方法:该方法会拦截所有的目标对象的方法
- 产生代理对象,可以直接利用代理器处理器类,可单独写一个类;
- 缺点:目标对象的所有方法都会被拦截处理。将来可以根据方法对象的属性判断是否需要加入事务操作。
- 静态代理
静态代理
创建服务业务的接口
package lesson2.proxy;public interface UserService { public void inertUser(); public void updateUser(); public void deleteUser();}
实际业务实现接口
package lesson2.proxy;public class UserServiceImpl implements UserService{ @Override public void inertUser() { // System.out.println("开启事务"); System.out.println("通过一个or多个dao操作完成增加用户的业务"); // System.out.println("提交事务,如果有异常就需要回滚事务"); } @Override public void updateUser() { // System.out.println("开启事务"); System.out.println("通过一个or多个dao操作完成修改用户的业务"); // System.out.println("提交事务,如果有异常就需要回滚事务"); } @Override public void deleteUser() { System.out.println("通过一个or多个dao操作完成删除用户的业务"); }}
代理实现接口
package lesson2.proxy;public class UserServiceProxy implements UserService{ private UserService userService; public void setUserService(UserService userService) { this.userService = userService; } @Override public void inertUser() { System.out.println("开启事务,日志,权限~~~~"); userService.inertUser(); System.out.println("提交事务,如果有异常就需要回滚事务"); } @Override public void updateUser() { System.out.println("开启事务"); userService.updateUser(); System.out.println("提交事务,如果有异常就需要回滚事务"); } @Override public void deleteUser() { System.out.println("开启事务"); userService.deleteUser(); System.out.println("提交事务,如果有异常就需要回滚事务"); }}
测试类
package lesson2.proxy;/** * 静态代理测试 * @author hh * */public class ProxyDemo1 { public static void main(String[] args) { UserServiceImpl us = new UserServiceImpl(); UserServiceProxy uproxy=new UserServiceProxy(); uproxy.setUserService(us); // us.updateUser(); // us.inertUser(); uproxy.updateUser(); uproxy.inertUser(); }}
动态代理
可以发现静态代理中,要做的辅助操作(实务,日志)在每个业务方法中都要进行重写,繁琐。
代理处理器 代理工厂
package lesson2.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class ProxyFactoryBean implements InvocationHandler { private Object target;// 目标对象 --->调用目标对象的任何方法都会被invoke方法拦截。 public ProxyFactoryBean(Object target) { this.target = target; } /** * 参数method 方法拦截后,拦截的目标对象的方法。 args 就是方法的参数。 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //可以根据方法对象的特点来判断是否需要加入事务操作 System.out.println("开启事务 日志 权限等操纵"); method.invoke(target, args); // 目标方法的调用 System.out.println("提交事务,如果有异常就需要回滚事务"); return null; } /** * 第一个参数:目标对象的类加载器 * 第二个参数:对象所实现的接口 * 第三个参数:代理处理器类 * @return */ public Object getProxy() { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); }}
测试类
package lesson2.proxy;/** * 动态代理测试 * @author hh * */public class ProxyDemo2 { public static void main(String[] args) { UserServiceImpl us = new UserServiceImpl(); //目标对象 //代理处理器、代理工厂 ProxyFactoryBean pfb= new ProxyFactoryBean(us); //产生代理对象 UserService usProxy = (UserService)pfb.getProxy(); usProxy.deleteUser(); usProxy.updateUser(); usProxy.inertUser(); }}
用代理模式完成操作
- 转账业务
- 添加业务
- 查询业务(不需要启动业务) 通过注解实现 是否需要事务 注解要加在接口上提炼事务的操作
- 事务的提交回滚包装到专门的类中
创建业务接口
package lesson2.proxyaccount;import java.util.List;import lesson2.Account;public interface AccountService { /** * 增加账户 * @param account * @return */ public int addAccount(Account account); /** * 转账 * @param id1 * @param id2 * @param money */ public void changeAccount(int id1,int id2,int money); /** * 查询所有 * @return */ @Support public List<Account> getAll();}
实际业务操作(实现接口方法)
package lesson2.proxyaccount;import java.util.List;import lesson2.Account;import lesson2.AccountDao;import lesson2.UserDao;public class AccountServiceImpl implements AccountService{ private AccountDao adDao = new AccountDao(); private boolean flag; @Override public int addAccount(Account account) { int n =adDao.addAccount(account); return n; } @Override public void changeAccount(int id1, int id2, int money) { Account account1 = adDao.findById(id1); Account account2 = adDao.findById(id2); //省略用户不存在或者账户余额不足的操作。 int n1=adDao.updateAccount(id1,account1.getMoney()-money); if(flag){ //模拟出错 throw new RuntimeException("未知错误"); } int n2=adDao.updateAccount(id2,account2.getMoney()+ money); } @Override @Support public List<Account> getAll() { List<Account> accounts =adDao.getllAccount(); return accounts; }}
动态代理操作(实现接口)
package lesson2.proxyaccount;import java.lang.reflect.InvocationHandler;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.sql.Connection;import java.sql.SQLException;import lesson2.JdbcUitl;public class ProxyFactoryBean implements InvocationHandler { private Object target; public ProxyFactoryBean(Object target) { super(); this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] arg) { Support support = method.getAnnotation(Support.class); if(support!=null&& support.value().equals("none")){ try { proxy= method.invoke(target,arg); System.out.println("没有事务"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally{ JdbcUitl.closeConnection(); } return proxy; } return proxyMerhod(proxy, method, arg); } private Object proxyMerhod(Object proxy, Method method, Object[] arg) { // Connection con = JdbcUitl.getConn(); try { // 开始事务 // con.setAutoCommit(false); TransactionManager.begin(); proxy=method.invoke(target, arg); // 业务调用 // con.commit(); // 提交事物 TransactionManager.commit(); } catch (Exception e) { e.printStackTrace(); try { // con.rollback(); // 业务回滚 TransactionManager.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } finally { JdbcUitl.closeConnection(); // 业务关闭 } } return proxy; } public Object getProxy() { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); }}
事务处理(开始,提交,回滚)
package lesson2.proxyaccount;import java.sql.Connection;import java.sql.SQLException;import lesson2.JdbcUitl;public class TransactionManager { public static void begin()throws SQLException{ Connection con =JdbcUitl.getConn(); con.setAutoCommit(false); } public static void commit()throws SQLException{ Connection con =JdbcUitl.getConn(); con.commit(); } public static void rollback()throws SQLException{ Connection con =JdbcUitl.getConn(); con.rollback(); }}
用标签修饰方法
决定是否需要进行事务操作。例如查询所有就无需事务操作
package lesson2.proxyaccount;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Support { String value()default "none";}
标签要修饰在接口上
/** * 查询所有 * @return */ @Support public List<Account> getAll();
测试类
package lesson2.proxyaccount;import java.util.List;import lesson2.Account;public class AccountTest { public static void main(String[] args) { //未产生代理// AccountServiceImpl accountService = new AccountServiceImpl(); // accountService.changeAccount(1001, 1002, 100); //产生代理 AccountServiceImpl accountService = new AccountServiceImpl(); ProxyFactoryBean pfb = new ProxyFactoryBean(accountService); AccountService accountServiceProxy = (AccountService)pfb.getProxy(); //测试转账 accountServiceProxy.changeAccount(1001, 1002, 100); //测试增加一条记录 // Account account = new Account(1011, 100,"zhangsan2"); // accountServiceProxy.addAccount(account); //全部查询 List<Account> accounts = accountServiceProxy.getAll(); for (Account account : accounts) { System.out.println(account); } }}
写在最后
这是jdbc学习的第二篇笔记。
1 0
- JDBC(2)JAVA连接数据库之 分页操作、事务操作、代理模式
- jdbc连接Oracle数据库 AND 事务(统一事务操作)
- JDBC(3)JAVA连接数据库之 抽象DAO操作
- JDBC连接数据库操作步骤(JAVA)
- java jdbc 连接操作数据库
- java之 jdbc连接数据库与操作excel文件代码
- 连接数据库jdbc操作
- JDBC连接数据库操作
- jdbc连接数据库操作
- java采用jdbc连接操作数据库
- JAVA采用JDBC连接操作数据库详解
- Java操作Sqlite数据库-jdbc连接
- java 中 JDBC 连接数据库操作
- java中jdbc连接数据库操作
- java操作数据库(JDBC)
- 数据库操作之事务
- Java-数据库操作 事务操作
- JDBC连接数据库(oracle)操作
- 如何将maven的默认JRE1.5改成1.7修改方法
- STL剖析——空间配置器
- 常见的验证码与验证码识别工具详细实例解说
- 在Linux下使用TCP封装器来加强网络服务安全
- 如何 在 Mac OS X 里通过命令行获取 CPU 信息
- JDBC(2)JAVA连接数据库之 分页操作、事务操作、代理模式
- unity文件存储和读取
- SDL_Init函数
- 文章标题
- android IntentService分析
- 1209日常小结
- 按键70秒,Root轻松得:Linux惊现高危漏洞
- socket编程之bind()函数
- java 文件、文件夹 递归复制、移动