【Mybatis】SP02 通用Mapper 基础CRUD
编写Mapper测试类:
@Test public void selectOneTest() { // 查询一个记录,居然需要提供一个实例 // 实例的各个属性即筛选的要求 Employee employee = new Employee(2,null,null,null); employee = employeeMapper.selectOne(employee); log.info(employee.toString()); }
结果很正常的就报错了,因为一开始我们的数据库表名称并没有在Java中绑定注释
报错信息:
Caused by: java.sql.SQLSyntaxErrorException: Table 'common_mapper.employee' doesn't exist
解决办法是使用JPA规范提供的@Table注解
import javax.persistence.Table;
然后注解在实体类上面:
再次测试发现有报错了。。。原来表名创建的时候写歪了我日:
然后再次更改,测试:
总算成功了
DEBUG [main] - ==> Preparing: SELECT emp_id,emp_name,emp_salary,emp_age FROM tabple_emp WHERE emp_id = ? DEBUG [main] - ==> Parameters: 2(Integer) DEBUG [main] - <== Total: 1 DEBUG [main] - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@53dbe163] INFO [main] - Employee(emp_id=2, emp_name=jerry, emp_salary=6635.42, emp_age=38)
除了@Table注解,JPA规范还提供了@Column注解,用于绑定字段名称
再次测试查看结果:结果是依然可以的
DEBUG [main] - ==> Preparing: SELECT emp_id,emp_name,emp_salary,emp_age FROM tabple_emp WHERE emp_id = ? DEBUG [main] - ==> Parameters: 2(Integer) DEBUG [main] - <== Total: 1 DEBUG [main] - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1b835480] DEBUG [HikariPool-1 housekeeper] - HikariPool-1 - Pool stats (total=1, active=1, idle=0, waiting=0) INFO [main] - Employee(id=2, name=jerry, salary=6635.42, age=38)
selectByPrimaryKey();
@Test public void selectOneByPrimaryKeyTest() { Employee employee = employeeMapper.selectByPrimaryKey(1); log.info(employee.toString()); }
查询结果发现空指针:
java.lang.NullPointerException
这时在查看上面打印的SQL语句:
可这并不是我们希望的样子
DEBUG [main] - ==> Preparing: SELECT emp_id,emp_name,emp_salary,emp_age FROM tabple_emp WHERE emp_id = ? AND emp_name = ? AND emp_salary = ? AND emp_age = ? DEBUG [main] - ==> Parameters: 1(Integer), 1(Integer), 1(Integer), 1(Integer) DEBUG [main] - <== Total: 0
问题的原因通用Mapper 将实体类中的所有字段都拿来放在一起作为联合主键
解决方案居然是使用@Id注解标明数据表的主键字段
再次测试成功:
DEBUG [main] - ==> Preparing: SELECT emp_id,emp_name,emp_salary,emp_age FROM tabple_emp WHERE emp_id = ? DEBUG [main] - ==> Parameters: 1(Integer) DEBUG [main] - <== Total: 1 DEBUG [main] - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3549bca9] INFO [main] - Employee(id=1, name=tom, salary=1254.37, age=27)
用来判断提供的主键是否存在:
@Test public void selectOneByPrimaryKeyTest2() { boolean isExist = employeeMapper.existsWithPrimaryKey(5); Boolean wrapperResult = isExist; log.info(wrapperResult.toString()); }
测试结果:
DEBUG [main] - ==> Preparing: SELECT CASE WHEN COUNT(emp_id) > 0 THEN 1 ELSE 0 END AS result FROM tabple_emp WHERE emp_id = ?
DEBUG [main] - ==> Parameters: 5(Integer)
DEBUG [main] - <== Total: 1
插入实体实例操作:
@Test public void insertTest() { Employee employee = new Employee(null, "杰哥", 3300.00, 24); int insert = employeeMapper.insert(employee); log.info("操作结果:" + insert); }
测试结果:
DEBUG [main] - ==> Preparing: INSERT INTO tabple_emp ( emp_id,emp_name,emp_salary,emp_age ) VALUES( ?,?,?,? ) DEBUG [main] - ==> Parameters: null, 杰哥(String), 3300.0(Double), 24(Integer) DEBUG [main] - <== Updates: 1 DEBUG [main] - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3549bca9] INFO [main] - 操作结果:1
除了操作插入之外,还很贴心的给我们提供了返回自增主键的功能
但是需要注解设置:
获取方式:
@Test public void insertTest() { Employee employee = new Employee(null, "阿伟", 9300.00, 21); int insert = employeeMapper.insert(employee); Integer id = employee.getId(); log.info("操作结果:" + insert); log.info("自增返回的主键:" + id); }
测试结果:
DEBUG [main] - ==> Preparing: INSERT INTO tabple_emp ( emp_id,emp_name,emp_salary,emp_age ) VALUES( ?,?,?,? ) DEBUG [main] - ==> Parameters: null, 阿伟(String), 9300.0(Double), 21(Integer) DEBUG [main] - <== Updates: 1 DEBUG [main] - ==> Executing: SELECT LAST_INSERT_ID() DEBUG [main] - <== Total: 1 DEBUG [main] - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4748a0f9] INFO [main] - 操作结果:1 INFO [main] - 自增返回的主键:8
但是像Oracle采用序列主键的话,就需要单独再设置:
insertSelective方法:
带选择性的插入,所谓的选择性,就是一些字段值为NULL,SQL语句干脆就不注入这个字段
案例:
@Test public void selectiveInsertTest() { int insertSelective = employeeMapper.insertSelective(new Employee()); }
结果,除了主键的NULL注入,其他属性一律就没写给SQL中
DEBUG [main] - ==> Preparing: INSERT INTO tabple_emp ( emp_id ) VALUES( ? ) DEBUG [main] - ==> Parameters: null DEBUG [main] - <== Updates: 1 DEBUG [main] - ==> Executing: SELECT LAST_INSERT_ID() DEBUG [main] - <== Total: 1
我的演示可能不恰当,准且来说应该使用这个才对:
@Test public void selectiveInsertTest() { int insertSelective = employeeMapper.insertSelective(new Employee(null, null, null, null)); }
updateSelective方法:
上述的这种插入方法再这个修改的案例中,能体现的更为明显,
例如现在我们修改一条记录:
当前主键为8的记录的员工名称是阿伟,而我们希望改变成其他名称
这是我们的测试方法:
@Test public void selectiveUpdateTest() { int update = employeeMapper.updateByPrimaryKeySelective(new Employee(8, "空条承太郎", null, null)); }
后面的两个字段没有赋值,都为null,按照通常的理解,SQL语句的执行将会把这些为NULL的值也注入
那么来看结果:
DEBUG [main] - ==> Preparing: UPDATE tabple_emp SET emp_id = emp_id,emp_name = ? WHERE emp_id = ? DEBUG [main] - ==> Parameters: 空条承太郎(String), 8(Integer) DEBUG [main] - <== Updates: 1
实际改变的只有名称字段,那么这么做的好处,就是在编写修改操作的业务时,我们不需要携带记录的完整信息,
我们修改业务: 根据主键查询需要修改的记录,然后渲染在修改页上面,用户提交修改信息,再把完整的记录信息带回后台处理
如果有这样智能选择的操作,就只需要提供的必要的修改信息和主键就够了,又能少搬些砖了
deleteByPrimaryKey方法
使用DELETE方法注入NULL将会删除表的所有记录,切记
@Test public void deleteOneByPrimaryKey() { // 这样表示删除所有记录 int i = employeeMapper.delete(null); }
按主键删除:如果为空,筛选条件将不匹配
@Test public void deleteOneByPrimaryKey2() { int i = employeeMapper.deleteByPrimaryKey(null); }
selectRowBounds方法:
这个方法的限制查询非常与众不同,
先看测试类:
@Test
public void selectByRowBounds() {
int startingPosition = 3;
int sizeLimitation = 10;
RowBounds rowBounds = new RowBounds(startingPosition, sizeLimitation);
List<Employee> employeeList = employeeMapper.selectByRowBounds(new Employee(), rowBounds);
for (Employee employee : employeeList) {
log.info(employee.toString());
}
}
结果:
DEBUG [main] - ==> Preparing: SELECT emp_id,emp_name,emp_salary,emp_age FROM tabple_emp
DEBUG [main] - ==> Parameters:
DEBUG [main] - <== Total: 5
INFO [main] - Employee(id=4, name=kate, salary=2209.11, age=22)
INFO [main] - Employee(id=5, name=justin, salary=4203.15, age=30)
说明这个查询会从SQL中查询所有,再到程序中按照限制条件返回
@Transient注解用于排除非数据库表的字段属性