一、创建项目
二、导包
核心包
mybatis-3.2.1.jar
依赖包
asm-3.3.1.jar
cglib-2.2.2.jar
commons-logging-1.1.1.jar
javassist-3.17.1-GA.jar
log4j-1.2.17.jar
slf4j-api-1.7.2.jar
slf4j-log4j12-1.7.2.jar
数据库驱动包
mysql-connector-java-5.1.26-bin.jar
三、 准备数据
- 数据库
- 建库
- 建表
- 插入测试数据
- 项目
- 准备domain
- 准备dao和测试类
四、配置
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>
<!-- 引入Properties文件 -->
<!--
resource 默认去classpath中寻找资源
-->
<properties resource="jdbc.properties"/>
<!--
配置自定义别名
别名不区分大小写
一个一个配置:
typeAlias
type 类型的完全限定名
alias 别名
统一为某个包下的所有类起别名
package
name : 包名 别名就是类名(不区分大小写)
-->
<typeAliases>
<package name="cn.yun.mybatis.domain"/>
</typeAliases>
<!--
environments : 环境的集合
default: 默认使用哪个环境 值为环境的id
-->
<environments default="development">
<!--
environment : 一个环境,对应一个数据库
id: 环境的标识
-->
<environment id="development">
<!--
transactionManager:事务管理器
type="JDBC" 使用JDBC的事务进行提交和回滚
type="MANAGED" 它从不提交和回滚,而是让容器进行事务的管理
-->
<transactionManager type="JDBC"/>
<!--
dataSource : 数据源
type="UNPOOLED" 不使用连接池
type="POOLED" 使用连接池
type="JNDI" 容器中使用
-->
<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>
<mappers>
<!--注册映射文件-->
<mapper resource="ProductMapper.xml"/>
</mappers>
</configuration>
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mybatis
jdbc.username=root
jdbc.password=root
log4j.properties
#log4j.properties(日志文件:)
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
log4j.appender.stdout.layout.ConversionPattern=%d %p
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:根节点
namespace : 命名空间
今天写:domain的完全限定名+Mapper
domain:cn.itsource.mybatis._01_hello.domain.Product
namespace:cn.itsource.mybatis._01_hello.domain.ProductMapper
namespace在老版本中时可以不写的,
新版本中必须定义namespace属性
-->
<mapper namespace="cn.yun.mybatis.domain.ProductMapper">
<!--
select update insert delete :定义sql语句的地方
id:sql的标识 同一个namespace下不能重复
resultType:结果的类型
每一个结果的类型,完全限定名
-->
<select id="selectAll" resultType="Product">
select * from product
</select>
<!--
parameterType : 参数类型 完全限定名
#{id} 等同于?
-->
<select id="selectfindOne"
resultType="Product"
parameterType="long">
select * from product where id=#{id}
</select>
<!--删除-->
<delete id="delete" parameterType="long" >
delete FROM product WHERE id=#{id}
</delete>
<!--添加-->
<!--Mybatis获取主键:
* 只需要在insert标签中添加几个属性
* useGeneratedKeys = "true"
* keyColumn 表中的主键列列名 - 可以省略
* keyProperty domain中主键对应的成员变量-->
<insert id="inertSave" parameterType="Product" useGeneratedKeys="true" keyProperty="id">
INSERT INTO product(productName, dir_id,salePrice, supplier, brand,cutoff, costPrice)
VALUES (#{productName},#{dir_id},#{salePrice},#{supplier},#{brand},#{cutoff},#{costPrice})
</insert>
<update id="update" parameterType="product">
UPDATE product set productName=#{productName},dir_id=#{dir_id},salePrice=#{salePrice},
supplier=#{supplier}, brand=#{brand},cutoff=#{cutoff},costPrice=#{costPrice}
WHERE id=#{id}
</update>
</mapper>
工具类
package cn.yun.mybatis.util;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MybatisUtil {
private static SqlSessionFactory factory = null;
static {
try {
factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("MyBatis-Config.xml"));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取Sqlsession对象
* @return
*/
public static SqlSession getSqlSession(){
SqlSession sqlSession = factory.openSession();
return sqlSession;
}
/**
* 释放资源
*/
public static void close(SqlSession sqlSession){
if (sqlSession != null){
sqlSession.close();
}
}
}
ProudentImpl
package cn.yun.mybatis.dao.imp;
import cn.yun.mybatis.dao.IProductDao;
import cn.yun.mybatis.domain.Product;
import cn.yun.mybatis.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import java.util.List;
public class ProudentImpl implements IProductDao {
private final String NAMESPACE = "cn.yun.mybatis.domain.ProductMapper.";
@Override
public void save(Product prodect) {
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtil.getSqlSession();
int insert = sqlSession.insert(NAMESPACE + "inertSave",prodect);
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
MybatisUtil.close(sqlSession);
}
}
@Override
public void update(Product proudect) {
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtil.getSqlSession();
sqlSession.update(NAMESPACE+"update",proudect);
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
MybatisUtil.close(sqlSession);
}
}
@Override
public void delete(Long id) {
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtil.getSqlSession();
int delete = sqlSession.delete(NAMESPACE + "delete",id);
sqlSession.commit();//提交事务,在数据库表选项引擎改成InnoDB
} catch (Exception e) {
e.printStackTrace();
} finally {
MybatisUtil.close(sqlSession);
}
}
@Override
public Product findOne(Long id) {
SqlSession sqlSession =null;
Product product =null;
try {
sqlSession = MybatisUtil.getSqlSession();
product = sqlSession.selectOne(NAMESPACE + "selectfindOne",id);
} catch (Exception e) {
e.printStackTrace();
} finally {
MybatisUtil.close(sqlSession);
}
return product;
}
@Override
public List<Product> findAll() {
SqlSession sqlSession =null;
List<Product> list = null;
try {
sqlSession = MybatisUtil.getSqlSession();
list = sqlSession.selectList(NAMESPACE+"selectAll");
} catch (Exception e) {
e.printStackTrace();
} finally {
MybatisUtil.close(sqlSession);
}
return list;
}
}
测试
private IProductDao productDao = new ProudentImpl();
@Test
public void testSave() throws Exception{
Product product = productDao.findOne(1L);
product.setProductName("天华");
productDao.save(product);
获取新添加数据的主键,前提insert标签已经配置了那三个属性
System.out.println(product.getId());//获取新添加数据的主键
}
五、注意事项:
- ① 我们的映射文件一般情况下是和它对应的domain实体类在同一个层级
- ② 这个映射文件的名称一般叫做 XxxMapper.xml (Xxx代表的是实体类名称)
- ③ namespace的名称为了确定唯一性,请大家根据我的要求取名
如我们有一个类:
cn.itsource.domain.Product / cn.itsource.domain.Student
那这里取名应该是:
cn.itsource.domain.ProductMapper /cn.itsource.domain.StudentMapper - ④ 类型都通通使用全限定名
六、三大核心对象
- SqlSessionFactoryBuilder
目的是创建SqlSessionFactory 用完就扔 写在方法内部 作为局部变量
建造者模式 - SqlSessionFactory
重量级对象 作用域整个应用 单例模式使用 有二级缓存 - SqlSession
轻量级的 请求作用域,一个请求对应一个SqlSession对象 线程不安全的 有一级缓存 - Executor 数据库的操作都是调用的Executor接口的方法
update
query
#{}的使用
-
(1)如果传入的是一个简单参数 基本数据类型(包装类型)、字符串类型
#{xxx} xxx只是起到占位符的作用,内容可以随便写 -
(2)如果传入的是一个复杂参数 Map domain
#{xxx} xxx必须和成员变量名称对象,底层调用该属性的get方法从参数对象中获取值
${}的使用
${} 不管是什么参数,都是调用属性的get方法,$中的内容必须是成员变量名称
#{}和${}的区别
-
$:
INSERT INTO product ( productName, dir_id, salePrice, supplier, brand, cutoff, costPrice ) VALUES ( ‘ROG3’, 3, 182.0, ‘罗技’, ‘罗技’, 0.8, 80.0 ) -
#:
INSERT INTO product ( productName, dir_id, salePrice, supplier, brand, cutoff, costPrice ) VALUES ( ?, ?, ?, ?, ?, ?, ? ) -
#的原理:预编译的sql语句 ==》 ?
-
$的原理: 字符串的拼接 拼接sql
什么时候选择哪种方式?
-
(1)能使用#就用#,不能用#的时候才选择使用$
-
?不能代替表名和字段名 #{}
select * from ? (X)
select * from product where ?=? (X)select * from ${tableName}
.Log4j日志框架
- 在使用MyBatis的很多时候,我们需要把日志打印出来,帮助我们进行分析与排错。
- 打开后我们可以看到执行的SQL语句,可以看到我们传递的参数。
- 而MyBatis中打印日志使用的是Log4j
- Log4j简介:
- Log4j有三个主要的组件:Loggers(记录器),Appenders (输出源)和Layouts(布局)。
- 可简单理解为日志类别,日志要输出的地方和日志以何种形式输出。综合使用这三个组件可以轻松地记录信息的类型和级别,并可以在运行时控制日志输出的样式和位置。
- .日志等级
等级从低到高
TRACE:详细
Debug:调试,类似于System.out.print
Info:信息,类似于JPA打印sql等级
Warn:警告,程序可以正常运行,出现提示
Error:错误,出现异常
- og4j.properties
#log4j.properties(日志文件:)
log4j.rootLogger=ERROR, stdout
#log4j.rootLogger=NONE
log4j.logger.cn.yun=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
- 注意:在上面的标红部分是我们需要修改的,它大概表示为当前会打印哪些位置下面文件的日志。
cn.yun:一定要根据自己的包名情况进行修改
如果配置成功,那么在MyBatis运行操作数据时就可以看到相应的日志了。
MyBatis中为一个类取别名
- 内置别名
如:
parameterType=“long”
<!--删除-->
<delete id="delete" parameterType="long" >
delete FROM product WHERE id=#{id}
</delete>
- 自定义别名
<typeAliases>
<!--
将一个包下面的所有类都取上别名:<package name="cn.yun.domain" />
alias:取的别名
type:这个别名所对应的Java类
:别名使用的时候与大小写无关
-->
<typeAlias alias="product" type="cn.yun.domain.Product" />
<!-- 做项目的时候使用 -->
<package name="cn.yun.mybatis.domain" />
</typeAliases>
列名与属性名不对应的解决方案
- .resultMap:在MyBatis中,提供了一个resultMap的标签,就是让咱们来完成返回结果的关系对应的
<!--
返回的数据映射
type:代表是要映射的对象
id:代表唯一(过会我们要拿到它)
-->
<resultMap type="cn.yun.domain.Product" id="productMap">
<!--
column:对应的列名
property:对应的属性名
-->
<id column="id" property="id" />
<result column="productName" property="name" />
</resultMap>
<select id="queryOne" parameterType="long" resultMap="productMap">
select * from product where id = #{id}
</select>
- 传递一个Map对象
<select id="get" parameterType="map" resultType="cn.itsource.mybaits.domain.User">
select * from t_user where name=#{name} and password=#{password}
</select>