概念
MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索。
- 简化JDBC的开发
- 能够更好的完成ORM(对象关系映射)
Spring mybatis的使用方式:
第一步:创建核心配置文件,配置全局文件,数据库,映射文件,加载驱动,合并了配置的相关信息。
//核心映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- mybatis的核心配置文件,配置了事务管理,数据源 -->
<configuration>
<!--environments可以配置多个数据库的连接信息,default指定默认的环境-->
<environments default="test">
<environment id="test">
<!--使用的事务管理器-->
<transactionManager type="JDBC"></transactionManager>
<!--配置了数据源-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/> //加载JDBC驱动
<property name="url" value="jdbc:mysql://localhost:3306/mybatisdb?characterEncoding=utf8&serverTimezone=Asia/Shanghai" /> //设置访问的数据库
<property name="username" value="root"/> //配置数据库的账号
<property name="password" value="root"/> //配置数据库的密码
</dataSource>
</environment>
</environments>
<!--引入映射文件--> //加载映射文件
<mappers>
映射文件的文件地址
<mapper resource="UserMapper.xml"></mapper>
</mappers>
</configuration>
对应的普通JDBC编写方式:
//普通JDBC的编写方式
Class.forName("com.mysql.jdbc.Driver")
String URL = "JDBC:mysql://localhost:3306/mybatisdb?
characterEncoding=utf8&serverTimezone=Asia/Shanghai";
Connection c = DriverManager.getConnection(URL,user,password);
第二步:建立映射文件
<!--映射文件-->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--这个文件是映射文件,写SQL的,namespace用来作为一个mapper.xml文件的唯一标识-->
<mapper namespace="userMapper">
<!-- 查id=1的用户信息
id是这条SQL的唯一标识,名称尽量描述该语句的效果
resultType的值用来封装查到的结果,ORM-->
<select id="getById" resultType="cn.tedu.pojo.User">
select * from user id=1
</select>
<!-- 查所有的的用户信息-->
<select id="getUser" resultType="cn.tedu.pojo.User">
select * from user
</select>
</mapper>
对应部分的普通JDBC编写方式:
//普通JDBC的编写方式
String sql="sql语句"
PreparedStatement ps = c.prepareStatement(sql);
ps.setObject(1,条件1);
ps.setObject(1,条件2);
ps.setObject(1,条件3);
....
第三步,第四步:建立会话工厂,进行会话,并展示数据
//加载配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//建立会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//使用会话工厂建立会话
SqlSession session = factory.openSession();
//使用会话窗口进行会话
Object o = session.selectOne("userMapper.getById");
//查询需要填入的内容为MXL文件名+查询方法的id值
List<User> list = session.selectList("userMapper.getUser");
//展示数据
System.out.println(o); //展示单个数据
System.out.println(list); //展示多个数据
for(User u:list){ //使用for循环单行展示多个数据
System.out.println(u);
}
查询需要填入的内容为MXL文件名.查询方法的id值
Object o = session.selectOne("userMapper.getById");
对应部分的普通JDBC编写方式:
//对应部分的普通JDBC编写方式:
ResultSet r = ps.executeQuery(); //发起查询并返回数据
ps.executeUpdate(); //发起增删改数据请求
//展示单个数据
if(r.next())
{
int rId = r.getInt(1);
String rname = r.getString(2);
String rAddr = r.getString(3);
int rAge = r.getInt(4);
}
//单行展示多个数据
List<Object> list = null;
while(r.next())
{
for(int i=1;list.add(r.getString(i);i++);
}
System.out.println(list);
Spring mybatis的优点:
后续维护方便:
1. 与JDBC相比,减少了50%以上的代码量。准备框架的时候需要其他文件作为配置,但是后续只需要修改映射文件即可解决大部分的添加任务,不必重复添加驱动及连接数据库。
2. MyBatis相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL写在XML里,从程序代码中彻底分离,降低耦合度,便于统一管理和优化,并可重用,维护方便
3.提供XML标签,支持编写动态SQL语句。
4.提供映射标签,支持对象与数据库的ORM字段关系映射。
Spring mybatis后续映射文件内sql任务的添加:
<!--sql任务的添加-->
<!--查询name="sayhi"的所有数据-->
<select id="getSayhi" resultType="cn.tedu.pojo.User">
select * from user where name="sayhi"
</select>
对应的查询命令:Object sayhi = session.selectOne("userMapper.getsayhi");
<!--查询user="sayhi"的密码-->
<select id="getSayhiPass" resultType="cn.tedu.pojo.User">
select password from user where user="sayhi"
</select>
对应的查询命令:Object o = session.selectOne("userMapper.getSayhiPass");
<!--查询所有的用户名-->
<select id="getAllUser" resultType="cn.tedu.pojo.User">
select * from user
</select>
对应的查询命令:List<User> list = session.selectList("userMapper.getAllUser");
//查询到的结果较多,使用selectList来获取一个列表,多个数据,而不是selectOne获取单个数据
<!--查询特定id的用户信息-->
<select id="getById" resultType="cn.tedu.pojo.User">
select * from user where id=#{id}
</select>
对应的查询命令:Object o = session.selectOne("userMapper.getById",2);//查询id=2的用户信息
<!--查询特定用户的用户信息-->
<select id="getUser" resultType="cn.tedu.pojo.User">
select * from user where name=#{name}
</select>
对应的查询命令:Object user = session.selectOne("userMapper.getUser","sayhi");
//查询用户名为sayhi的用户信息
SQL中有特殊字符
当SQL中有特殊字符,mybatis不能正常解析时,
用<![CDATA[ ?? ]]>括起来就解决了 <![CDATA[ and age<=#{age} ]]>
<![CDATA[and age<=#{age}]]>
SQL中的$,¥和#
在须输入查询目标的查询中可以使用$,¥来代替#,但是¥输入的是目标值的本身,不会主动为输入目标添加“”。所以少用或不用$或¥尽量用#
为目标对象添加别名:
为了避免输入别名时出现错误,可以在配置文件中设置别名。简化输入,减少错误
//为目标对象添加别名
<typeAliases>
<typeAlias type="cn.tedu.pojo.User" alias="User"/>
<!--typeAlias type="目标所在的地址" alias="别名"-->
</typeAliases>
使用接口开发:
为优化SQL的字符串拼接过程,namepase的地方可以采用id的值。
在调用session的方法的时候,都会传入要调用的SQL的namespace+id名称,这不是必须的。可以只传入id即可。但是,如果在mybatis的环境中有多个相同id的映射名称,就会报错。所以,一般情况下,调用方法最好还是使用namespace+id。但是,namespace+id的使用方式很容易报错,因为是string类型的,没有检查。所以,mybatis提供了一种非常好的设计方式来避免这种问题,即Mapper接口。
<!--使用接口开发-->
<mapper namespace="接口的全路径">
<!-- 查id=1的部门信息
id是这条SQL的唯一标识
resultType的值用来封装查到的结果,ORM
-->
<select id="接口的方法" resultType="Dept">
select * from dept where id=1
</select>
</mapper>
//接口文件
public interface 接口文件名字{
返回类型 getById();
}
//查询 命令
接口文件名字mapper = session.getMapper(接口文件名字.class); //获取接口的文件
Object o = mapper.getById(); //通过接口调用指定方法
System.out.println(o);
使用命令获取接口的文件 DeptMapper mapper = session.getMapper(DeptMapper.class);
mapper 接口文件的对象,DeptMapper.class接口文件
通过接口文件使用接口的方法,通过接口的方法获取值。Object o = mapper.getById();
o:最终需要查询的对象,
mapper.getById():获取对象中的方法
getById()方法:
<mapper namespace="接口的全路径">
<select id="接口的方法" resultType="Dept">
select * from dept where id=1
</select></mapper>
1. 使用接口查询所有的用户名
2.查询特点id的用户名
用户名name,接口文件名为UserMapper,接口方法为getAllUser()
XmL文件:
<mapper namespace="cn.tedu.Dao.UserMapper">
<!-- 查id=1的部门信息
id是这条SQL的唯一标识
resultType的值用来封装查到的结果,ORM
-->
<select id="getAllUser" resultType="User"> //id为接口名 resultType为别名
select name from User //sql语句
</select>
<select id="getUser" resultType="User"> //id为接口名 resultType为别名
select name from User where id=#{id} //sql语句
</select>
</mapper>
//接口文件
public interface DeptMapper { //接口文件名
List getAllUser(); //接口方法
User getUser(int id); //接口方法
}
//查询语句
public void get() throws IOException {
//加载配置文件
InputStream input = Resources.getResourceAsStream("mybatis-config.xml");
//建立会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(input);
//建立会话
SqlSession session= factory.openSession();
//加载接口文件
UserMapper mapper = session.getMapper(UserMapper.class);
//使用接口查询
List<Object> list = mapper.getAllUser();
Object o = mapper.getUser();
//输出查询结果
System.out.println(list);
System.out.println(o);
}
添加数据库的增删改方法
//映射文件
<insert id="save">
insert into dept value(#{id},#{dname},#{loc})
</insert>
<insert id="add">
insert into dept value(null,#{dname},#{loc})
</insert>
//在接口文件中添加接口
void save(Dept dept);
void add(String dname,String loc);
//提交命令
Dept dept = new Dept(); //给与固定的id值插入数据
dept.setDname("java培训部").setLoc("杭州").setId(100);
mapper.save(dept);
mapper.add("java","西安"); //给与空的id值,让数据库自增添加
session.commit();//对数据库的增删改都需要自己提交事务!!!!
注意错误1:
org.apache.ibatis.exceptions.PersistenceException:
### Error updating database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '10' for key 'PRIMARY'
### The error may exist in DeptMapper.xml
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: insert into dept value(?,?,?)
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '10' for key 'PRIMARY'
原因:id是主键,主键10已有数据,无法重复提交!
注意错误2:提交命令无报错但是数据库不添加数据
提交数据后一定要加入session.commit();
对数据库的增删改都需要自己提交事务!!!
动态SQL
概述:动态sql指利用mybatis框架的一些标签完成SQL的拼接写出更通用,更有效的SQl语句
常用标签:
sql,提取SQL片段
include:引入指定的sql片段
if:满足条件拼接sql,不满足跳过
where:
修改映射文件,实现动态SQL(SQl拼接)
/*<sql>截取select语句*/
<sql id="cols"> /*截取select id,dname,loc from id值为cols
select id,dname,loc from
</sql>
<select id="getDname" resultType="Dept">
//插入截取id值为cols的sql语句:select id,dname,loc from
<include refid="cols"></include>
dept
<where> //拼接if并去掉条件中可能多余的and或者or:
<if test="id!=null">where id=#{id}</if> //如果id!=null则加入where id=#{id}
<if test="dname!=null">where dname=#{id}</if> //如果id!=null则加入where id=#{id}
</where>
</select>
方法接口的重载:
在使用动态sql的技术之下,可以做到查询某一个用户与全部用户共用一条语句
/*<sql>截取select语句*/
<sql id="cols"> /*截取select id,name,loc from id值为cols
select id,name,loc from
</sql><select id="getName" resultType="Dept">
//插入截取id值为cols的sql语句:select id,name,loc from
<include refid="cols"></include>
dept
<where> //拼接if并去掉条件中可能多余的and或者or:
<if test="id!=null">where id=#{id}</if> //如果id!=null则加入where id=#{id}
<if test="dname!=null">where name=#{id}</if> //如果id!=null则加入where id=#{id}
</where>
</select>
此时若是有输入值,则查询对应要求的结果,若是无输入值则查询全部结果,因此延伸出多个接口
getName(Integer id,String name,String loc);
getName(Integer id);
getName(String name);
getName(String loc);
getName();
此时表现得就是接口的重载,虽然输入参数不同,但最终执行的都是同一个select模块。