mybatis操作数据的两种方式:原生api和mapper代理对象
1.mybatis的api提供的方法
- insert() 增加 delete() 删除 update() 更新
- selectOne() 返回一个数据
- selectList() 返回多个数据,结果类型为List
- selectMap() 返回多个数据,结果类型为Map
- select() 返回特殊格式的数据(策略+回调)
原生api总结:
1.不用写开Connection,给?存值等繁琐的jdbc代码
2.总清单文件只写一次,子清单文件可以写多个,都放的sql语句
3.调用原生api,指定好sql语句的id,参数类型和结果类型即可
4.修改sql语句只需要修改子清单文件,不用修改源代码
5.针对查询而言,返回的数据结构(集合)丰富,不用程序员把ResultSet中的数据转换为集合对象。
mapper代理对象模式:底层用法还是原生api
2.连接数据库操作流程
(1)连接池池数据源关闭所有连接(关掉老连接)
(2)开启 jdbc
(3)创建连接connection,即mysql的连接对象
(4)seting autocommit to false开链接 ,开启事务
(5)根据方法ID在user.xml的找到对应id 的sql语句
- preparing预编译,(statement每个造执行计划,非常耗费时间)
- 参数、返回值
(6)事务关闭
(7)关闭jdbc
(8)将连接还到连接池内
补充说明:
1.只要异常中的sqlSession为null,就一定是清单文件中有错误
2.给mybatis项目添加日志输出
a.导入log4j.jar
b.在项目的类路径下添加一个log4j.properties,logging初始化, ibatis日志管理实现适配器
连接数据库的时候可能存在的编码问题:
java.sql.SQLException: Unknown initial character set index ‘255‘ received from server.-CSDN博客
3.数据库操作
select语句提供了很丰富的结果数据结构
3.1 增删改查
rowAffect=sqlSession.insert("insertUser",user);
rowAffect=sqlSession.delete("deleteUserById",id);
rowAffect=sqlSession.insert("insertUser",user);
红色标注部分为id, 根据对应Id在子清单文件中找到sql语句,并执行
xxDao.java
public int addUser(User user);
public int deleteUser(Integer id);
public int updateUser(User user);
xxDaoImpl.java
public int addUser(User user) {
int rowAffect=0;
SqlSession sqlSession=null;
try {
sqlSession=MybatisUtil.getSession();
rowAffect=sqlSession.insert("insertUser",user);
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally {
if(sqlSession!=null){
sqlSession.close();
}
}
return rowAffect;
}
@Override
public int deleteUser(Integer id) {
int rowAffect=0;
SqlSession sqlSession=null;
try {
sqlSession=MybatisUtil.getSession();
rowAffect=sqlSession.delete("deleteUserById",id);
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally {
if(sqlSession!=null){
sqlSession.close();
}
}
return rowAffect;
}
@Override
public int updateUser(User user) {
int rowAffect=0;
SqlSession sqlSession=null;
try {
sqlSession=MybatisUtil.getSession();
rowAffect=sqlSession.update("updateUser",user);
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally {
if(sqlSession!=null){
sqlSession.close();
}
}
return rowAffect;
}
user.xml子清单文件
<!--插入用户-->
<insert id="insertUser"
parameterType="org.example.entity.User">
insert into t_user(
user_name,
user_password,
address)
values(
#{name},
#{password},
#{address}
);
</insert>
<!--删除用户-->
<delete id="deleteUserById"
parameterType="java.lang.Integer">
delete from t_user
where id=#{id};
</delete>
<!--根据id更新用户-->
<update id="updateUser"
parameterType="org.example.entity.User">
update t_user set
user_name=#{name},
user_password=#{password},
address=#{address}
where
id=#{id}
</update>
单元测试:
@Test
public void addUser() {
UserDao userDao=new UserDaoImpl();
//假数据
User user=new User();
user.setName("add");
user.setPassword("654321");
user.setAddress("测试用例");
Integer rowAffect=userDao.addUser(user);
System.out.println(rowAffect);
}
@Test
public void deleteUser() {
UserDao userDao=new UserDaoImpl();
Integer rowAffect=userDao.deleteUser(3);
System.out.println(rowAffect);
}
@Test
public void updateUser() {
UserDao userDao=new UserDaoImpl();
//假数据
User user=new User();
user.setId(3);
user.setName("addUser");
user.setPassword("654321");
user.setAddress("单元测试");
Integer rowAffect=userDao.updateUser(user);
System.out.println(rowAffect);
}
结果展示:
增加一个数据User
更新id=3的数据
删除id=3的数据
特别的:子清单文件中<insert>、<select>等标签并没有进行判断,Mybatis仅对语句进行判断然后执行。从底层调用来说update\insert调用的是同一个底层方法
3.2 selectOne
查询并返回一个结果
xxDao.java
public User findUserById(Integer id);
xxDaoImpl.java
@Override
public User findUserById(Integer id) {
User user=null;
SqlSession sqlSession=null;
try {
sqlSession=MybatisUtil.getSession();
user=sqlSession.selectOne("findUserById",1);
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally {
if(sqlSession!=null){
sqlSession.close();
}
}
return user;
}
user.xml
<!--根据id获得用户信息-->
<select id="findUserById"
resultType="org.example.entity.User"
parameterType="java.lang.Integer">
select
id,
user_name as name,
user_password as password,
address
from t_user
where id = #{id}
</select>
单元测试:
@Test
public void findUserById() {
UserDao userDao=new UserDaoImpl();
User user=userDao.findUserById(1);
System.out.println(user);
}
结果展示:
3.3selectList
查询并返回一个List类型的结果,List里的数据类型可以是业务对象类型,如User; 也可以以Map<Integer,Object> 形式返回对象信息,map中的key是属性名,值是属性值。
xxDao.java
//返回list结构
public List<User> findAllUser1();
public List<Map<String,Object>> findAllUser2();
xxDaoImpl.java
@Override
public List<User> findAllUser1() {
List<User> userList=null;
SqlSession sqlSession=null;
try {
sqlSession=MybatisUtil.getSession();
userList=sqlSession.selectList("findAllUser1SqlId");
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally {
if(sqlSession!=null){
sqlSession.close();
}
}
return userList;
}
@Override
public List<Map<String, Object>> findAllUser2() {
List<Map<String, Object>> userList=null;
SqlSession sqlSession=null;
try {
sqlSession=MybatisUtil.getSession();
userList=sqlSession.selectList("findAllUser2SqlId","id");
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally {
if(sqlSession!=null){
sqlSession.close();
}
}
return userList;
}
user.xml
<!--查所有返回list<User>-->
<select id="findAllUser1SqlId"
resultType="org.example.entity.User"
>
select
id,
user_name as name,
user_password as password,
address
from t_user
</select>
<!--查所有返回list<Map>-->
<select id="findAllUser2SqlId"
resultType="java.util.Map"
>
select
id,
user_name,
user_password,
address
from t_user
</select>
单元测试:
@Test
public void findAllUser1() {
UserDao userDao=new UserDaoImpl();
List<User> userList=userDao.findAllUser1();
for(User user:userList){
System.out.println(user);
}
}
@Test
public void findAllUser2() {
UserDao userDao=new UserDaoImpl();
List<Map<String, Object>> userList=userDao.findAllUser2();
for(Map<String, Object> user:userList){
System.out.println(user.toString());
}
}
结果展示:
返回List<User>
返回List<Map<String,Object>>
3.4selectMap
查询并返回一个Map类型的结果,key是指定的属性,Map里的key值数据类型可以是业务对象类型,如User; 也可以以Map<Integer,Object> 形式返回对象信息,map中的key是属性名,值是属性值。
userMap=sqlSession.selectMap("findAllUser3SqlId","id");
userMap=sqlSession.selectMap("findAllUser3SqlId","id");
红色表示将id指定为最外层Map的key值, 也可将其他属性设置为key值。
xxDao.java
//返回map结构
public Map<Integer,User> findAllUser3();
public Map<Integer,Map<String,Object>> findAllUser4();
xxDaoImpl.java
@Override
public Map<Integer, User> findAllUser3() {
Map<Integer, User> userMap=null;
SqlSession sqlSession=null;
try {
sqlSession=MybatisUtil.getSession();
//这里是将id作为key了
userMap=sqlSession.selectMap("findAllUser3SqlId","id");
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally {
if(sqlSession!=null){
sqlSession.close();
}
}
return userMap;
}
@Override
public Map<Integer, Map<String, Object>> findAllUser4() {
Map<Integer, Map<String, Object>> userMap=null;
SqlSession sqlSession=null;
try {
sqlSession=MybatisUtil.getSession();
//这里是将id作为key了
userMap=sqlSession.selectMap("findAllUser4SqlId","id");
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally {
if(sqlSession!=null){
sqlSession.close();
}
}
return userMap;
}
user.xml
<!--查所有返回Map<User>-->
<select id="findAllUser3SqlId"
resultType="org.example.entity.User"
>
select
id,
user_name as name,
user_password as password,
address
from t_user
</select>
<!--查所有返回Map<Map>-->
<select id="findAllUser4SqlId"
resultType="java.util.Map"
>
select
id,
user_name,
user_password,
address
from t_user
</select>
单元测试:
@Test
public void findAllUser3() {
UserDao userDao=new UserDaoImpl();
Map<Integer,User> userMap=userDao.findAllUser3();
for(Integer key:userMap.keySet()){
System.out.println(key+"——>"+userMap.get(key).toString());
}
}
@Test
public void findAllUser4() {
UserDao userDao=new UserDaoImpl();
Map<Integer,Map<String,Object>> userMap=userDao.findAllUser4();
for(Integer key:userMap.keySet()){
System.out.println(key+"——>"+userMap.get(key).toString());
}
}
结果展示:
Map<String,Object>
Map<String,Map<String,Object>>
3.5select返回自定义数据结构
select()是mybatis留给程序员的自定义接口,其可以返回程序员自定义的数据结构,可以回一个map,也可以是实体对象
这里以JsonString 为指定数据结果为例进行实现
select()可以处理自定义的特殊结构,
ResultHandler<> 是带泛型的接口,我们自定义的resultHandler,如JsonResultHandler 均实现ResultHandler<>接口
其中:
@Override
public void handleResult(ResultContext<? extends User> resultContext) {}
handleResult没有返回值,通过额外的方法将结果进行返回,如 public String getJson(){}
resultHandler处理数据结构的过程:
resultHandler中handleResult每调用一次,处理一个对象
返回一个数据,将数据处理为指定类型
循环调用处理结果集中的所有对象
xxDao.java
//自定义结构返回
public String findAllUser5();
xxDaoImpl.java
为了返回指定的数据结构,我们在resultHandler里设定返回格式。
@Override
public String findAllUser5() {
String users=null;
SqlSession sqlSession=null;
try {
sqlSession=MybatisUtil.getSession();
//循环多次
JsonResultHandler resultHandler=new JsonResultHandler();
sqlSession.select("findAllUser5SqlId",resultHandler);
users=resultHandler.getJson();
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally {
if(sqlSession!=null){
sqlSession.close();
}
}
return users;
}
//内部类
class JsonResultHandler implements ResultHandler<User>{
//用于追加内容
StringBuilder sb=new StringBuilder("[");
//回调一次,返回一个对象
//结构: ["1":{1:2,2:3},"2":{1:2,2:3}]
@Override
public void handleResult(ResultContext<? extends User> resultContext) {
//获取用户数据
User user=resultContext.getResultObject();
//封装成json串
sb.append("{");
sb.append("\"id\":");
sb.append(user.getId()+",");
sb.append("\"name\":");
sb.append("\""+user.getName()+"\",");
sb.append("\"password\":");
sb.append("\""+user.getPassword()+"\",");
sb.append("\"address\":");
sb.append("\""+user.getAddress()+"\"");
sb.append("}");
sb.append(",");
}
public String getJson(){
String temp=sb.toString();
//前包后不包
String temp1= temp.substring(0,temp.length()-1)+"]";
return temp1;
}
}
user.xml
<!--查所有返回自定义格式-->
<select id="findAllUser5SqlId"
resultType="org.example.entity.User"
>
select
id,
user_name as name,
user_password as password,
address
from t_user
</select>
单元测试
@Test
public void findAllUser5() {
UserDao userDao=new UserDaoImpl();
String usersJson=userDao.findAllUser5();
System.out.println(usersJson.toString());
}
结果展示
总结:
- Mybatis 中的 ResultHandler 相当于数据结果集的处理器,它是一个回调函数(Callback),用来处理每一行数据的结果,这个回调函数可以在查询结果处理到一定量时触发,对结果集数据进行定制化处理。
- ResultHandler 的使用可以大幅提升数据处理的效率,当我们需要处理大量的数据时,一般会使用 ResultHandler 来进行结果的处理,避免一次查询就全部返回结果,浪费内存资源或造成 OOM。
摘自《5.7 mybatis之ResultHandler流式处理数据_resulthandler 修改导出数据-CSDN博客》
- mybatis中的原生 api 方法,select(),实现原理是策略模式 + 方法回调,select可以返回我们自定义的数据格式,例如json
摘自《面向接口编程+策略模式+方法回调一起使用_面向接口编程中接口回调怎么写-CSDN博客》
4.设计模式
策略模式: Mybatis的select()方法底层实现是策略模式+回调
策略模式
- 策略模式(Strategy Pattern)属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。
- 其主要目的是通过定义相似的算法,替换if else 语句写法,并且可以随时相互替换。
摘自《https://www.cnblogs.com/xuwujing/p/9954263.html》
5.补充
数据库的游标是什么,有什么用?
1.什么是游标?
游标Cursor是处理数据的一种方法,用来查看或者处理结果集中的数据,游标提供了在结果集中一次一行或者多行向前或向后浏览数据的能力;
游标相当于一个指针,它可以指定结果中的任何位置,允许用户对指定位置的数据进行处理;
游标可以被看作是一个临时文件,提供了在查询结果集中向前或向后浏览护具、处理结果集中数据的能力。
2.游标的作用是什么?
游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录进行处理的机制。
用户可以访问结果集中任意一行数据,在将游标放置到某行之后可以在该行或从该位置的行块上执行操作。
其实就是用于存放查询出来的多条记录的一个临时变量,我们可以从这个变量中取出我们需要的信息字段。摘自《https://www.cnblogs.com/wanyuy/p/17098457.html》
类的内部类?
内部类可以访问该类定义所在操作域的所有数据,包括私有操作域
内部类可以对该包下的其他类隐藏
内部类可以“破解”java单继承的缺陷摘自《java----内部类(四种内部类详解)-CSDN博客》
为什么说Mybatis是面向接口编程?
面向接口编程:就是为了处理对象之间的协作关系,去实现类之间的通信,模块之间的交互等等而设计出来的编程思想。
MyBatis在采用面向接口编程时,采用实体+接口+映射文件的方式。其中接口是不需要实现类的。
摘自《Mybatis学习笔记5:面向接口编程、注解开发_面向对象编程 mybatis-CSDN博客》
摘自《MyBatis学习总结(三)---面向接口编程_mybatis技术-接口编程 实验总结-CSDN博客》
注意:
- sql书写时,列名和属性名对应
- 同一个命名空间下,id不同相同
- preparedStatement可以防止sql注入
- springjdbc同结构——rowMapper