一:走进MyBatis
框架:
1:是一系列jar包,其本质是对JDK功能的拓展.
2:框架是一组程序的组合,包含了一系列的最佳实践,作用是解决某一个领域的问题.
WEB开发中的最佳实践:根据职责的纵向划分:控制层 业务层 持久层
控制层:WEB/MVC: 负责处理页面交互的相关操作(Struts2/Spring MVC)
业务层:service: 负责复杂的业务逻辑计算和判断(Spring)
持久层:dao: 负责将业务逻辑数据进行持久化存储(MyBatis/Hibernate)
最佳实践图:
ORM框架:
遵循ORM思想实现的技术,解决的是持久层的问题(和数据库做CRUD):
一个良好的持久层应该保证:
当持久层的实现技术改变的时候,不会影响上一层的代码(service).
ORM思想图:
MyBatis:
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎
所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,
将接口和 Java 的 POJOs(PlainOld Java Objects,普通的 Java对象)映射成数据库中的记录。
https://mybatis.github.io/mybatis-3/zh/index.html 手册里面足够学习了
二:基础操作:
MyBatis依赖jar包: 在github下载里面有好多好的项目源码 多动手敲代码
1):MySQL驱动包:mysql-connector-java-5.1*jar
2):核心包:mybatis-3.54.jar
3):其他依赖.lib目录中所有的jar(有需要再拷贝)
mysql-connector-java-5.1.40.jar
MyBatis的配置文件AND映射文件:
MyBatis-Config.xml
日志文件的输出:
先拷贝jar包:
slf4j-api-1.7.21.jar
slf4j-log4j12-1.7.21.jar
并配合log4j-1.2.17.jar一起使用
log4j.properties文件内容:
#设置全局的日志配置:输出Error级别,输出到控制台 日志的级别:ERROR>WARN>INFO>DEBUG>TRACE级别越低,输出的信息越详细
log4j.rootLogger=ERROR, stdout
#设置自定义的日志级别 每次记得修改包名
log4j.logger.cn.wolfcode.mybatis.hello=TRACE
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
OGNL表达式:
resultMap:
主要解决表的列名跟属性名称不匹配的问题:
Mapper接口:
Mapper接口的原理:动态代理:Spring的时候重点来讲解
Mapper组件
参数处理:
//方式一:把多个参数封装成一个JavaBean
Client login1(LoginVO vo);
//方式二:使用Map对象来封装多个参数
Client login2(Map<String, Object> paramMap);
//方式三:使用Param注解,原理是方式二
Client login3(@Param("username")String username,@Param("password")String password);
List<Client> login4(@Param("orderby")String orderby);
<select id="login1" parameterType="LoginVO" resultType="client">
SELECT id,username,password FROM client Where username = #{username}
AND password = #{password}
</select>
<select id="login2" parameterType="map" resultType="client">
SELECT id,username,password FROM client Where username = #{username1}
AND password = #{password1}
</select>
<select id="login3" resultType="client">
SELECT id,username,password FROM client Where username = #{username}
AND password = #{password}
</select>
<select id="login4" resultType="client">
SELECT id,username,password FROM client
ORDER BY ${orderby}
</select>
@Test
public void testLogin1() throws Exception {
LoginVO vo = new LoginVO("will","1111");
SqlSession session = MyBatisUtil.getSession();
ClientMapper clientMapper = session.getMapper(ClientMapper.class);
Client client = clientMapper.login1(vo);
session.close();
System.out.println(client);
}
@Test
public void testLogin2() throws Exception {
Map<String,Object> paramMap = new HashMap<String,Object>(){
{
this.put("username1", "will");
this.put("password1", 1111);
}
};
SqlSession session = MyBatisUtil.getSession();
ClientMapper clientMapper = session.getMapper(ClientMapper.class);
Client clietn = clientMapper.login2(paramMap);
session.close();
System.out.println(clietn);
}
@Test
public void testLogin3() throws Exception {
SqlSession session = MyBatisUtil.getSession();
ClientMapper clientMapper = session.getMapper(ClientMapper.class);
Client clietn = clientMapper.login3("will","1111");
session.close();
System.out.println(clietn);
}
@Test
public void testLogin4() throws Exception {
SqlSession session = MyBatisUtil.getSession();
ClientMapper clientMapper = session.getMapper(ClientMapper.class);
List<Client> clietn = clientMapper.login4("id desc");
session.close();
for (Client c : clietn) {
System.out.println(c);
}
}
参数处理:
MyBatipse插件:
MyBatipse是Eclipse的一个插件,提供了内容提示和MyBatis的配置文件验证功能!
三:注解开发
开发和配置MyBatis框架:
方式一:使用XML配置,把SQL和映射写在XML文件中. 推荐!
方式二:使用注解配置,把SQL和映射写在JAVA代码中(Mapper接口).
public interface UserMapper {
@Insert("insert into t_user value (#{id},#{name},#{salary})")
@Options(useGeneratedKeys=true,keyProperty="id")
void save(User u);
@Update("UPDATE t_user set name = #{name}, salary = #{salary} where id = #{id}")
void update(User u);
@Delete("DELETE FROM t_user WHERE id = #{id}")
void delete(Long id);
@Select("SELECT * FROM t_user WHERE ID = #{id}")
@Results(id="BaseResultMap",value={
@Result(column="id",property="id"),
@Result(column="name",property="name"),
@Result(column="salary",property="salary")
})
User get(Long id);
@Select("SELECT * FROM t_user")
@ResultMap("BaseResultMap")
List<User> listAll();
}
既然修改了mapper文件,那么
mybatis-config.xml文件中修改为<mapper> <mappec class=""/> </mapper>
四:动态SQL
choose:选择,跟if else 一个意思
<choose>
<when test="deptId > 0"> AND deptId = #{deptId}</when>
<otherwise>AND deptId IS NOT NULL</otherwise>
</choose>
Where:若果条件以AND或者OR开头,就应该替换为WHERE
set:如果中间以有值就输入,最后一个去掉逗号,
<set>
<if test="name!=null">
name = #{name},
</if>
<if test="password != null">
password = #{password},
</if>
</set>
trim:可以替代where 跟set 一般不用
trim的作用图:
mapper文件:
public interface EmployeeMapper {
List<Employee> query(
@Param("minSalary")BigDecimal minSalary,
@Param("maxSalary")BigDecimal maxSalary,
@Param("deptId") Long deptId
);
void batchDelete(@Param("ids") List<Long> ids);
void batchSave(@Param("emps") List<Employee> emps);
}
<!--
foreach元素:
collection属性:表示对哪一个集合或数组做迭代
如果参数是数组类型,此时Map的可以为array
如果参数是List类型,此时Map的key为list
我们可以在参数上使用Param注解,规定死Map中key是什么.@Param("ids")
open属性:在迭代集合之前,拼接什么符号.
close属性:在迭代集合之后,拼接什么符号.
separator属性:在迭代元素时,每一个元素之间用什么符号分割开来.
item属性:被迭代的每一个元素的变量
index属性:迭代的索引
-->
<delete id="batchDelete">
DELETE employee where id in
<foreach collection="ids" open="(" close=")" separator="," item="id">
#{id}
</foreach>
</delete>
mysql的批量插入:
<insert id="batchSave">
inset into employee (name,sn,salary) values
<foreach collection="emps" separator="," item="e">
(#{e.name},#{e.sn},#{e.salary})
</foreach>
</insert>
查询操作:
<select id="query" resultType="Employee">
SELECT id,name,sn,salary,deptId From employee
<where>
<if test="minSalary!=null">
AND salary >= #{minSalary}
</if>
<if test="maxSalary">
AND salary <= #{maxSalary}
</if>
<choose>
<when test="deptId > 0"> AND deptId = #{deptId}</when>
<otherwise>AND deptId IS NOT NULL</otherwise>
</choose>
</where>
</select>
bind:可以吧重复的小段代码提出来用
sql:把重复的代码包装起来利用他的id调用
include:文件中插入sql的代码.
分页查询: 回顾一下这一篇博客的知识点
domain
<select id="query" resultType="Employee">
SELECT id,name,sn,salary,deptId From employee
<where>
<if test="minSalary!=null">
AND salary >= #{minSalary}
</if>
<if test="maxSalary">
AND salary <= #{maxSalary}
</if>
<choose>
<when test="deptId > 0"> AND deptId = #{deptId}</when>
<otherwise>AND deptId IS NOT NULL</otherwise>
</choose>
</where>
</select>
mapper
public interface EmployeeMapper {
List<Employee> queryForList(QueryObject qo);
int queryForCount(QueryObject qo);
}
<mapper namespace="cn.wolfcode.mybatis.hello.mapper.EmployeeMapper">
<sql id="base_where">
<where>
<if test="keyword != null and keyword != ''">
<bind name="keywordLike" value="'%'+keyword+'%'"/>
AND (name like #{keywordLike} OR sn LIKE #{keywordLike})
</if>
<if test="minSalary!=null">
AND salary >= #{minSalary}
</if>
<if test="maxSalary!=null">
AND salary <= #{maxSalary}
</if>
<if test="deptId > 0">
AND deptId = #{deptId}
</if>
</where>
</sql>
<!-- 查询结果集 -->
<select id="queryForList" resultType="Employee">
Select id,name,sn,salary,deptId FROM employee
<include refid="base_where" />
<if test="pageSize > 0">
LIMIT #{start},#{pageSize}
</if>
</select>
<!-- 查询结果总数 -->
<select id="queryForCount" resultType="int">
SELECT COUNT(id) FROM employee
<include refid="base_where" />
</select>
</mapper>
query
@Getter
@Setter
public class EmployeeQueryObject extends QueryObject{
private String keyword;
private BigDecimal minSalary;
private BigDecimal maxSalary;
private Long deptId = -1L;
public String getKeyword(){
return employ2null(keyword);
}
}
@Getter
public class PageResult {
private List<?> result;
private int totalCount;
private int currentPage = 1;
private int pageSize = 3;
private int prevPage;
private int nextPage;
private int totalPage;
public PageResult(List<?> result, int totalCount, int currentPage, int pageSize) {
this.result = result;
this.totalCount = totalCount;
this.currentPage = currentPage;
this.pageSize = pageSize;
this.totalPage = totalCount % pageSize == 0 ? totalCount % pageSize : totalCount % pageSize + 1;
this.prevPage = currentPage - 1 >= 1 ? currentPage - 1 : 1;
this.nextPage = currentPage + 1 <= totalPage ? currentPage + 1 : totalPage;
currentPage = currentPage > totalPage ? totalPage : currentPage;
}
}
@Getter
@Setter
public class QueryObject {
private int currentPage = 1;
private int pageSize = 3;
public int getStart() {
return (currentPage - 1) * pageSize;
}
//如果说字符串为空字符串,也应该设置为null
public String employ2null(String str) {
return hasLength(str) ? str : null;
}
public boolean hasLength(String str) {
return str != null && !"".equals(str.trim());
}
}
service
public interface IEmployeeService {
PageResult query(QueryObject qo);
}
impl
public class EmployeeServiceImpl implements IEmployeeService{
private EmployeeMapper employeeMapper = MyBatisUtil.getMapper(EmployeeMapper.class);
public PageResult query(QueryObject qo) {
int rows = employeeMapper.queryForCount(qo);
if(rows == 0){
return new PageResult(Collections.EMPTY_LIST,0,1,qo.getPageSize());
}
List<Employee> result = employeeMapper.queryForList(qo);
return new PageResult(result,rows,qo.getCurrentPage(),qo.getPageSize());
}
}
MyBatisUtil
public class MyBatisUtil {
private static SqlSessionFactory factory = null;
static{
InputStream in;
try {
//创建SqlSessionFactory对象
in = Resources.getResourceAsStream("mybatis-config.xml");
factory = new SqlSessionFactoryBuilder().build(in);
} catch (IOException e) {
e.printStackTrace();
}
}
//返回一个SqlSession对象
public static SqlSession getSession(){
//默认false不自动提交事务
return factory.openSession();
}
public static <T> T getMapper(Class<T> mapperClass){
return getSession().getMapper(mapperClass);
}
}
mybatis-config.xml
<configuration>
<properties resource="db.properties">
</properties>
<!-- 日志技术 -->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<typeAliases>
<!-- <typeAlias type="cn.wolfcode.mybatis.hello.User" alias="User"/> -->
<!-- 一般写到domain包就可以了,自动为该包中的类起别名,默认的别名就是简单类名首字母小写,其实不区分大小写 -->
<package name="cn.wolfcode.mybatis.hello"/>
</typeAliases>
<!-- 1:配置数据库的环境 -->
<environments default="dev">
<!-- 开发环境:在以后事务管理器和连接池都是交给Spring框架来管理的 -->
<environment id="dev">
<!-- ①:事务管理器 -->
<transactionManager type="JDBC"/>
<!-- ②:连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 2:关联映射文件 -->
<mappers>
<mapper resource="cn\wolfcode\mybatis\hello\mapper\EmployeeMapper.xml"/>
</mappers>
</configuration>