1 mybatis基本认识
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
MyBatis 是一个支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。
MyBatis 消除了几乎所有的JDBC代码和手工设置参数以及结果集的检索
。
mybatis相较于jdbc的优点
把sql语句从java代码中抽取出来,方便维护。并且修改sql时不用修改java代码
不用手动设置参数和对结果集的处理-让我们操作数据库更加简单
2 初识mybatis
2.1 导包
mybatis核心包mybatis/mybatis-3.2.1.jar
mybatis的依赖包 mybatis/lib/*.jar
jdbc驱动包 mysql-connector-java-5.1.26-bin.jar
2.2 基础准备(数据库表,domain层)
创建数据库表product
创建domain类Product
public class Product {
private Long id;
//品牌名称
private String productName;
//成本价
private double costPrice;
//销售价
private double salePrice;
//供应商
private String supplier;
//品牌
private String brand;
//折扣
private double cutoff;
//品牌类型
private Long dir_id;
get()/set()方法
}
2.3 创建配置文件
2.3.1 mybatis的核心配置 :mybatis-config.xml
<?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">
<!--configuration:配置(xml的根)-->
<configuration>
<!--引入jdbc.properties文件-->
<properties resource="jdbc.properties" />
<!--
environments:环境(多个环境)
default:代表多个环境中 用的哪一个环境
-->
<environments default="development">
<!--
environment:某一个环境
id:这个环境的名称
-->
<environment id="development">
<!--
transactionManager:事务管理
type:类型
type=”[JDBC|MANAGED]”)
JDBC:简单JDBC事物
MANAGED:啥都不做
-->
<transactionManager type="JDBC"/>
<!--
dataSource:数据源(连接池)
POOLED:mybatis内置的连接池
-->
<dataSource type="POOLED">
<!--
driver:驱动
driver:地址
-->
<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>
<mappers>
<!--引入写sql的xml-->
<mapper resource="cn/itsource/dao/ProductMapper.xml"/>
</mappers>
</configuration>
2.3.2 数据库的参数:jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mybatis
jdbc.username=root
jdbc.password=123456
2.3.3 ProductMapper.xml
<?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">
<!--
mapper:根(每个xml都得有,不用管它的含义)
namespace:命名空间(随便取个名称)
-->
<mapper namespace="cn.itsource.dao.ProductMapper">
<!--
select:代表这是一个查询语句
id:代表这个查询语句的唯一命名
以后你要找到这条SQL: namespace+id
例:cn.itsource.dao.ProductMapper.getOne
parameterType:参数类型
long -> Long _long -> long
resultType:返回的每一条结果的类型
注:返回类型的全限定名
-->
<select id="getOne" parameterType="long" resultType="cn.itsource.domain.Product">
select * from product where id = #{id}
</select>
</mapper>
2.4 完成测试
- 搞到配置文件 mybatis-config.xml
- 拿到核心对象 SqlSession
- SqlSession就可以CRUD
public class MyBatisTest {
/**
* 1、搞到配置文件 mybatis-config.xml
* 2、拿到核心对象 SqlSession
* 3、SqlSession就可以CRUD
*/
//查询单条数据
@Test
public void testHello()throws Exception{
//1、搞到配置文件 mybatis-config.xml
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//2、获取 SqlSessionFactory 对象
//SqlSessionFactoryBuilder --> SqlSessionFactory -> SqlSession
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(reader);
//拿到核心对象 SqlSession
SqlSession session = factory.openSession();
//3、获取到一个对象
Product product = session.selectOne("cn.itsource.dao.ProductMapper.getOne", 1L);
System.out.println(product);
//关闭session
session.close();
}
}
3 抽取工具类&CRUD
- SqlSessionFactoryBuilder:只用于创建factory,用完就可以扔掉
- SqlSessionFactory:重级量对象,创建后不要随便销毁(一个项目一个这个对象即可)
- SqlSession :用于完成咱们的CRUD
3.1 MyBatisUtil类
/**
* MyBatis的工具类
*/
public class MyBatisUtil {
//定义一个SqlSessionFactory对象
private static SqlSessionFactory factory = null;
static {
try {
factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));
}catch (Exception e){
e.printStackTrace();
}
}
public static SqlSession openSession(){
return factory.openSession();
}
}
3.2 完成CRUD
3.2.1 productMapper.xml配置sql
<?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">
<!--namespace:命名空间-->
<mapper namespace="cn.itsource.dao.ProductMapper">
<!--
select:代表这是一个查询语句
id:代表这个查询语句的唯一命名
(以后要找到这条sql:通过namespace + id)
例:cn.itsource.dao.ProductMapper.getOne
parameterType:参数类型
long -> Long _long -> long
resultType:返回的每一条结果的类型
注:返回类型的全限定名
-->
<select id="getOne" parameterType="long" resultType="product">
select *
from product
where id = #{id}
</select>
<!--
#和$的区别:
获取值的区别
$: 拿到的是传过来的对象的某一个属性
#:既可以单独那对象,还可以拿传过来的对象的某一个属性
对SQL的影响
#是预编译的方案(防sql注入,安全性更高,性能也会更强一些)
结论:
能使用#就使用#(优先使用#)
-->
<select id="queryOne" parameterType="productQuery" resultType="product">
select *
from product
where id = ${id}
</select>
<select id="getAll" resultType="product">
select *
from product
</select>
<delete id="delete" parameterType="long">
delete
from product
where id = #{id}
</delete>
<!--
useGeneratedKeys="true" 是否要主键
keyColumn="id" 在数据库中叫什么名字
keyProperty="id" 在类中叫什么名字
-->
<insert id="save" parameterType="product" useGeneratedKeys="true" keyColumn="id"
keyProperty="id">
insert into product (productName, costPrice, salePrice, supplier, brand, cutoff, dir_id) VALUE (#{productName},
#{costPrice},
#{salePrice},
#{supplier},
#{brand},
#{cutoff},
#{dir_id})
</insert>
<update id="update" parameterType="product">
update product
set productName=#{productName},
costPrice=#{costPrice},
salePrice=#{salePrice},
supplier=#{supplier},
brand=#{brand},
cutoff=#{cutoff},
dir_id=#{dir_id}
where id = #{id}
</update>
</mapper>
3.2.2 ProductDaoImpl实现层完成相应功能
package cn.itsource.dao.impl;
import cn.itsource.dao.IProductDao;
import cn.itsource.domain.Product;
import cn.itsource.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import java.util.List;
public class ProductDaoImpl implements IProductDao {
private final String NAMESOACE = "cn.itsource.dao.ProductMapper.";
//添加
@Override
public void save(Product product) {
SqlSession session = null;
try {
session = MyBatisUtil.openSession();
session.insert(NAMESOACE+"save",product);
//提交事物
session.commit();
}catch (Exception e){
//回滚事物
session.rollback();
e.printStackTrace();
}finally {
session.close();
}
}
//修改
@Override
public void update(Product product) {
SqlSession session = null;
try {
session = MyBatisUtil.openSession();
session.update(NAMESOACE+"update",product);
//提交事物
session.commit();
}catch (Exception e){
//回滚事物
session.rollback();
e.printStackTrace();
}finally {
session.close();
}
}
//删除
@Override
public void delete(Long id) {
SqlSession session = null;
try {
session = MyBatisUtil.openSession();
session.delete(NAMESOACE+"delete",id);
//提交事物
session.commit();
}catch (Exception e){
//回滚事物
session.rollback();
e.printStackTrace();
}finally {
session.close();
}
}
//查询单条数据
@Override
public Product findOne(Long id) {
SqlSession session = null;
try {
session = MyBatisUtil.openSession();
return session.selectOne(NAMESOACE+"getOne", id);
}catch (Exception e){
e.printStackTrace();
}finally {
session.close();
}
return null;
}
//查询所有数据
@Override
public List<Product> findAll() {
SqlSession session = null;
try {
session = MyBatisUtil.openSession();
return session.selectList(NAMESOACE+"getAll");
}catch (Exception e){
e.printStackTrace();
}finally {
session.close();
}
return null;
}
}
4 mybatis细节
4.1 添加的对象的时候返回id
<!--
useGeneratedKeys="true" 是否要主键
keyColumn="id" 在数据库中叫什么名字
keyProperty="id" 在类中叫什么名字
-->
<insert id="save" parameterType="product" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into product
(productName,dir_id,salePrice,supplier,brand,cutoff,costPrice) values
(#{productName},#{dir_id},#{salePrice},#{supplier},#{brand},#{cutoff},#{costPrice})
</insert>
4.2 自定义别名配置
- 内置别名(int,long,…)/自定义别名(自己的类)
- 别名不区分大小写
- 自定义别名的配置
- 每个对象单独配置别名
<typeAlias type="cn.itsource.domain.Product" alias="Product" />
- 扫描包(这个包的对象都会取别名)
<package name="cn.itsource.domain" />
<!--
定义别名
typeAliases:配置别名
type:类型
alias:别名
-->
<typeAliases>
<!--<typeAlias type="cn.itsource.domain.Product" alias="product" />-->
<!--为这个包下面所有的类都取别名-->
<package name="cn.itsource.domain" />
<package name="cn.itsource.query" />
</typeAliases>
4.3 日志的处理
在资源根目录创建一个log4j.properties
# ERROR错误的日志 WARN:警告 INFO:普通信息 DEBUG:调试日志 TRACE:日志
log4j.rootLogger=ERROR, stdout
#log4j.rootLogger=NONE
#把左边包名改成你自己的包名
log4j.logger.cn.itsource=TRACE
# 日志打印到控制台中
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
# 日志打印的一种格式(可以灵活地指定布局模式)
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# 日志打印的格式是什么样子的 %d:日期 %p:优先级 %c:类的全名 %m:输出的结果 %n:换行
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
4.4 #与$的区别
#和$的区别:
获取值的区别
$: 拿到的是传过来的对象的某一个属性
#:既可以单独那对象,还可以拿传过来的对象的某一个属性
对SQL的影响
#是预编译的方案(防sql注入,安全性更高,性能也会更强一些)
结论:
能使用#就使用#(优先使用#)
5 批量操作&动态修改
5.1 批量添加
sql: insert into 表名 (列名,列名) values (?,?),(?,?),...
xml配置
<!--
foreach:循环
collection:遍历的集合
item:每次遍历拿到的对象
separator:分隔符(每个值都使用,隔开)
-->
<insert id="batchSave" parameterType="list">
insert into employee (name, age, sex) values
<foreach collection="list" item="e" separator=",">
(#{e.name}, #{e.age}, #{e.sex})
</foreach>
</insert>
代码实现
//批量添加
@Test
public void testBatchSave()throws Exception{
List<Employee> list = new ArrayList<>();
for (int i = 1; i <= 20 ; i++) {
Employee employee = new Employee();
employee.setName("皮皮虾"+i);
employee.setAge(18+i);
employee.setSex(true);
list.add(employee);
}
SqlSession session = MyBatisUtil.openSession();
session.insert("cn.itsource.dao.EmployeeMapper.batchSave",list);
session.commit();
session.close();
}
5.2 批量删除
xml配置
<!--
foreach:循环
collection:遍历的集合
item:每次遍历拿到的对象
separator:分隔符(每个值都使用,隔开)
open:以什么开头
close:以什么结尾
index:遍历的索引
-->
<delete id="batchDelete" parameterType="list">
delete from employee where id in
<foreach collection="list" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
代码实现
//批量删除
@Test
public void testBatchDelete()throws Exception{
List<Long> ids = Arrays.asList(12L,14L);
SqlSession session = MyBatisUtil.openSession();
session.delete("cn.itsource.dao.EmployeeMapper.batchDelete",ids);
session.commit();
session.close();
}
5.3 动态修改
- 解决以前数据丢失问题
- 对象中没有值就不做修改
xml配置
<!--动态修改 只改有值的数据-->
<update id="dynamicUpdate" parameterType="employee">
update employee
<set>
<if test="name !=null">
name=#{name},
</if>
<if test="age !=null">
age=#{age},
</if>
<if test="sex !=null">
sex=#{sex},
</if>
</set>
where id = #{id}
</update>
代码实现
//动态修改
@Test
public void testDynamicUpdate()throws Exception{
Employee employee = new Employee();
employee.setId(5L);
employee.setName("皮皮怪啊啊啊啊啊");
employee.setSex(false);
SqlSession session = MyBatisUtil.openSession();
session.delete("cn.itsource.dao.EmployeeMapper.dynamicUpdate",employee);
session.commit();
session.close();
}