获得自增id
同样是插入用户后获得自增id,此时用的方法从update变成了insert,这个方法可以返回新增后的用户id,而无需自己再写一次last_insert_id()的sql语句获得,需要传入的参数有,sql, new ScalarHandler(),用户信息
/**
* 获得新增成功之后的id
*
* @param userInfo 完整的用户信息
* @return 自增的id
* @throws SQLException
*/
int insertUserInfoId(UserInfo userInfo) throws SQLException;
public int insertUserInfoId(UserInfo userInfo) throws SQLException {
return queryRunner.insert(
UserInfoSql.INSERT_USER_SQL,
new ScalarHandler<BigInteger>(),
userInfo.getUsername(),
userInfo.getAge(),
userInfo.getPass(),
userInfo.getImage(),
userInfo.getBirthday(),
userInfo.getRid()).intValue();
}
查询一个用户
第二个参数BeanHandler<>(Userinfo.class)
@Override
public Userinfo selectOneUser(int id) throws SQLException {
Userinfo query = q.query(UserInfoSql.SELECT_ONE_USER, new BeanHandler<>(Userinfo.class), id);
return query;
}
查询所有用户
此时第二个参数传的是BeanListHandler()
@Override
public List<UserInfo> findAllUserInfo() throws SQLException {
return queryRunner.query(
UserInfoSql.FIND_ALL_SQL,
new BeanListHandler<>(UserInfo.class, new BasicRowProcessor(new GenerousBeanProcessor())));
}
查询所有用户,并分页展示
List findAllUserPage(int page,int size) throws SQLException;
@Override
public List<UserInfo> findUserInfoByPage(int page, int size) throws Exception {
return queryRunner.query(
UserInfoSql.FIND_PAGE_SQL,
new BeanListHandler<>(UserInfo.class, new BasicRowProcessor(new GenerousBeanProcessor())),
(page-1)*size,size);
}
多表查询
将字段看作key,记录看作value,每行记录都是一个键值对,用Map存储,再用List集合将Map集合存储起来,用来装配的处理器是MapListHander()
@Override
public List<Map<String, Object>> findAllMgr() throws SQLException {
return q.query(UserInfoSql.SELECT_MGR, new MapListHandler());
}
事务
//数据库事务
//ACID 原子性 一致性 隔离性 持久性
// 隔离性:并发事务 根据隔离级别机制的不同 可能会产生不同的问题
//一共就有3个问题
//1. 脏读: 一个事务读到了另外一个事务没有提交的数据
//2. 不可重复读: 在一个事务内部 多次读取到数据 不一致的 (另外一个事务提交 insert/update)
//3.幻读: 在一个事务内部 与insert有关
//读未提交 read uncommitted 1 2 3
//读已提交 read committed 解决1 出现2 3
//可重复读 repeatable read 解决1 2 出现 3
//串行化(序列化) Serializable 解决 1 2 3
//机制越高 数据越安全 性能越低
//mysql: 可重复读
//oracle/sqlServer: 读已提交
模拟2个员工转账
开启事务需要在同一个数据源下,除此之外,想让两条sql语句变成一个事务,需要将自动提交更改为手动提交,通过两行代码使转账和收账处于同一事务下,更改手动提交需要借助数据源,这个数据源(从数据库连接池获得普通jdbc也可以)就是事务所使用的唯一数据源
测试:在不是一个数据源的情况下,无法处于一个事务,事务依然是自动提交
如何使用同一数据源:在dao层设置Connection属性,设置有参构造器,service层在创造对象时把数据源传过去,更新方法采用三个参数的(connection,sql,parameters)
//-- 7839 给 7369 转账
//-- 7839: sal-1000
//-- 7369: sal+1000
//
//UPDATE emp set sal=sal+1000 WHERE empno=7369;
//UPDATE emp set sal=sal-1000 WHERE empno=7839;
思路:
1.查询转账和被转账的对象(获得对象)
2…在service层处理转账动作(设置对象信息)
3.利用对象信息更新数据库信息
Test测试类
private static void transferAccounts() {
EmpService es = new EmpServiceImpl();
try {
//1.获取两个对象
Emp emp1 = u.selectEmpById(1011);
Emp emp2 = u.selectEmpById(1001);
//2.设置转账金额(为了避免丢精度选择Bigdecimal数据类型)
BigDecimal money = new BigDecimal("1000");
//3.开始转帐(需要处理两个对象中的信息,避免代码冗余,所以放到service层维护)
es.dispote(emp1,emp2,money);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
service处理转账
public class EmpServiceImpl implements EmpService {
@Override
public void dispote(Emp e, Emp e2, BigDecimal money) {
Connection conn = null;
try {
conn = DruidUtil.getDatasource().getConnection();
UserDao ud = new UserImpl(conn);
e.setSal(e.getSal().subtract(money));
e2.setSal(e2.getSal().add(money));
//一个sql是一个事务,设置手动提交 使处于同一事务
conn.setAutoCommit(false);
//开始转账
ud.updateEmp(e);
ud.updateEmp(e2);
System.out.println("转账成功");
DbUtils.commitAndClose(conn);
} catch (SQLException throwables) {
try {
DbUtils.rollbackAndClose(conn); //遇到异常回滚
} catch (SQLException sqlException) {
sqlException.printStackTrace();
}
throwables.printStackTrace();
}
}
}
dao层写获取对象和更新数据库的方法
public class UserImpl extends BaseDaoImpl<Userinfo> implements UserDao {
static QueryRunner q = new QueryRunner(DruidUtil.getDatasource());
private Connection conn;
public UserImpl(Connection conn) {
this.conn = conn;
}
public UserImpl(Class<Userinfo> tclass) {
super(tclass);
}
@Override
public void updateEmp(Emp e) throws SQLException {
q.update(conn,UserInfoSql.UPDATE_EMP,
e.getEname(),
e.getJob(),
e.getMgr(),
e.getHiredate(),
e.getSal(),
e.getComm(),
e.getDeptno(),
e.getEmpno());
}
@Override
public Emp selectEmpById(int id) throws SQLException {
List<Emp> execute = q.execute(UserInfoSql.SELECT_EMP,
new BeanHandler<>(Emp.class, new BasicRowProcessor(new GenerousBeanProcessor())),
id);
return execute.get(0);
}
模糊查询
private static void fuzzySearchByConditions() {
StringBuilder sql = new StringBuilder("select * from emp");
System.out.println("按 1.姓名 2.工作 3.无条件 查询(1,2,3)");
Scanner a = new Scanner(System.in);
String choice = a.next();
String[] s = choice.split(",");
Map<String,String> m = new HashMap<>(16);
for (String s1 : s) {
switch (s1) {
case "1":
System.out.println("请输入姓名:");
String name = a.next();
m.put("ename",name);
break;
case "2":
System.out.println("请输入工作:");
String job = a.next();
m.put("job",job);
case "3":
break;
}
}
if(m!=null)
{
sql.append(" where ");
Set<String> key = m.keySet();
for (String s1 : key) {
sql.append(s1).append(" like '%' ? '%'").append(" or ");
}
sql = sql.delete(sql.lastIndexOf("or"), sql.length());
}
System.out.println(sql);
try {
List<Emp> emps = u.likeQueryByConditions(sql.toString(), m);
for (Emp emp : emps) {
System.out.println(emp);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
dao层
@Override
public List<Emp> likeQueryByConditions(String sql, Map<String, String> m) throws SQLException {
Collection<String> values = m.values();
int index = 0;
String[] v = new String[2];
for (String value : values) {
v[index] = value;
index++;
}
List<Emp> query = q.query(sql, new BeanListHandler<>(Emp.class), v);
return query;
}