1、MyBatis的介绍
1. MyBatis 是一个支持普通SQL查询,存储过程和高级映射的优秀持久层(Dao)框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。
2. MyBatis 消除了几乎所有的JDBC代码和手工设置参数以及结果集的检索。
3. MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
4. 一个MyBatis的应用程序都以一个SqlSessionFactory 对象(单例)的实例为核心;
SqlSession对象完全包含以数据库为背景的所有执行SQL操作的方法。
5. MyBatis是针对数据库交互的一个辅助框架,也是对jdbc做了的简单封装,以xml配置代替Java代码来管理数据库的交互细节!!
注意:
JPA 可以自动建表。
MyBatis不能自动创建表,如果要建表,必须自己先准备好建表的sql语句。
MyBatis三大核心对象
1. SqlSessionFactoryBuilder
目的是创建SqlSessionFactory , 用完就扔 , 写在方法内部 , 作为局部变量 , 建造者模式。
2. SqlSessionFactory
重量级对象 , 作用域整个应用 , 单例模式使用 , 有二级缓存。
3. SqlSession
轻量级的 , 请求作用域,一个请求对应一个SqlSession对象 , 线程不安全的 , 有一级缓存。
4. (扩展)Executor 数据库的操作都是调用的Executor接口的方法
update:增、删、改所用方法。
query:查询所用方法。
MyBatis执行流程:
①:我们需要核心文件(提供联系数据库的环境)
②:需要映射文件(提供ORM与运行的SQL语句)
③:拿到SqlSession对象,用于执行SQL
2、MyBatis的入门使用
注意:
使用Mybatis的方式用两种,一种是xml配置的方式,一种是接口+注解的方式。
这里主要是介绍xml配置方式。
1.导入相应的jar包
核心包:mybatis-3.2.1.jar
数据库驱动包:mysql-connector-java-5.1.26-bin.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
2.准备相应的数据
数据库–>新建数据库–>新建表–>插入测试数据
3.准备domain实体类、dao和测试类
注意:类的名称和类型都和我们的product表相对应匹配
案例:
domain实体类
public class Product { private Long id; //商品名称 private String productName; //品牌 private String brand; //供应商 private String supplier; //零售价 private Double salePrice; //进价 private Double costPrice; //折扣比例 private Double cutoff; //商品分类编号 private Long dir_id;
-----之后是get、set方法(略)
}
dao层接口
public interface IProductDao { /** * 添加一个商品 */ void save(Product p); /** * 更新一个商品 */ void update(Product product); /** * 删除一个商品 */ void delete(Long id); /** * 查询一个商品 */ Product findOne(Long id); /** * 查询所有商品 */ List<Product> findAll(); }
dao层接口实现类
注:添加、修改、删除的时候一定要记住提交事务(配置事务、表结构支持事务)。
JDBC的事务是自动提交的,而JPA、Hibernate、MyBatis事务都是需要手动提交的。
package cn.wang.dao.daoImpl; import cn.wang.Utils.MyBatisUtils; import cn.wang.dao.IProductDao; import cn.wang.domain.Product; import org.apache.ibatis.session.SqlSession; import java.util.ArrayList; import java.util.List; public class ProductDaoImpl implements IProductDao { //抽取sql命名空间名字的值 private final String NAMESPACE = "cn.wang.domain.ProductMapper."; //添加方法 @Override public void save(Product p) { SqlSession sqlSession =null; try { //获取SqlSession对象(MyBatisUtils是为了方便专门抽取出来的工具类) sqlSession = MyBatisUtils.getSession(); //第一个参数:sql命名空间名字的值+对应sql语句映射的id,第二个参数:传入的值 sqlSession.insert(NAMESPACE+"insert",p); //提交事务 sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); } finally { //关闭sqlSession,释放资源(很重要,不然项目上线后会造成内存溢出) MyBatisUtils.colseSession(sqlSession); } } //修改方法 @Override public void update(Product product) { SqlSession sqlSession = null; try { //获取SqlSession对象(MyBatisUtils是为了方便专门抽取出来的工具类) sqlSession = MyBatisUtils.getSession(); //第一个参数:sql命名空间名字的值+对应sql语句映射的id,第二个参数:传入的值 sqlSession.update(NAMESPACE+"update", product); //提交事务 sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); } finally { //关闭sqlSession,释放资源(很重要,不然项目上线后会造成内存溢出) MyBatisUtils.colseSession(sqlSession); } } //删除方法 @Override public void delete(Long id) { SqlSession sqlSession=null; try { //获取SqlSession对象(MyBatisUtils是为了方便专门抽取出来的工具类) sqlSession = MyBatisUtils.getSession(); //第一个参数是获取查询语句:sql命名空间名字的值+对应sql语句映射的id sqlSession.delete(NAMESPACE+"delete", id); //提交事务 sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); } finally { //关闭sqlSession,释放资源(很重要,不然项目上线后会造成内存溢出) MyBatisUtils.colseSession(sqlSession); } } //查询一条数据 @Override public Product findOne(Long id) { SqlSession sqlSession = null; Product product= null; try { //获取SqlSession对象(MyBatisUtils是为了方便专门抽取出来的工具类) sqlSession = MyBatisUtils.getSession(); //第一个参数是获取查询语句:sql命名空间名字的值+对应sql语句映射的id product = sqlSession.selectOne(NAMESPACE+"findOne", id); } catch (Exception e) { e.printStackTrace(); } finally { //关闭sqlSession,释放资源(很重要,不然项目上线后会造成内存溢出) MyBatisUtils.colseSession(sqlSession); } return product; } //查询所有数据 @Override public List<Product> findAll() { SqlSession sqlSession=null; List<Product> list=new ArrayList<>(); try { //获取SqlSession对象(MyBatisUtils是为了方便专门抽取出来的工具类) sqlSession = MyBatisUtils.getSession(); //第一个参数是获取查询语句:sql命名空间名字的值+对应sql语句映射的id list=sqlSession.selectList(NAMESPACE+"findAll"); } catch (Exception e) { e.printStackTrace(); } finally { //关闭sqlSession,释放资源(很重要,不然项目上线后会造成内存溢出) MyBatisUtils.colseSession(sqlSession); } return list; } }
抽取出来的MyBatisUtils工具类
import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.Reader; public class MyBatisUtils { //保证sqlSessionFactory是单例 private static SqlSessionFactory sqlSessionFactory; // SqlSessionFactory类似于JPA的EntityManagerFactory,Hibernate的SessionFactory // SqlSession 类似于JPA的EntityManager,Hibernate的Session //该类被加载的时候就执行该静态代码块 static { try { Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); } catch (Exception e) {//异常的类型要写大一些,才能够看到具体的报错 e.printStackTrace(); } } //提供一个外界调用的类 public static SqlSession getSession(){ //创建并返回SqlSession对象 return sqlSessionFactory.openSession(); } //关闭sqlSession,释放资源(很重要,不然项目上线后会造成内存溢出) public static void colseSession(SqlSession sqlSession){ if(sqlSession !=null){ sqlSession.close(); } } }
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql:///数据库名称 jdbc.username=用户名 jdbc.password=密码
3.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> <!-- environments:环境集合 default:默认使用哪一个环境(必须对应一个环境的id) --> <!--引入外部的属性文件 不写classpath的原因:resources默认到classpath中寻找资源 --> <properties resource="jdbc.properties" /> <!-- 配置自定义别名 注意:别名不区分大小写。 共两种配置方式: 一:一个一个配置(typeAlias) type 类型的完全限定名 alias 别名 二:统一为某个包下的所有类起别名(package) name : 包名 别名就是类名(不区分大小写) --> <typeAliases> <!--方法一--> <!--<typeAlias type="cn.wang.domain" alias="Product"/>--> <!--方法二--> <package name="cn.wang.domain"/> </typeAliases> <environments default="development"> <!-- environment:一个环境 id:为这个环境取唯一一个id名称 --> <environment id="development"> <!-- transactionManager:事务管理(共有两个值) type:JDBC(支持事务)/MANAGED(什么都不做) --> <transactionManager type="JDBC" /> <!-- 数据源, 连接池 type(POOLED):MyBatis自带的连接池 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代表的是相应的ORM映射文件 --> <mappers> <mapper resource="cn/wang/domain/ProductMapper.xml" /> </mappers> </configuration>
4.配置映射文件(命名方式:domain实体类名称+Mapper.xml)
注意:
① 我们的映射文件在这里是和它对应的domain实体类在同一个层级
② 这个映射文件的名称一般叫做 XxxMapper.xml (Xxx代表的是实体类名称)
③ namespace的名称为了确定唯一性,请大家根据我的要求取名
如我们有一个类:
cn.itsource.domain.Product / cn.itsource.domain.Student
那这里取名应该是:
cn.itsource.domain.ProductMapper /cn.itsource.domain.StudentMapper
④ 类型都通通使用全限定名
<?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的主要功能就是写sql mapper:根 namespace:命令空间 (用来确定唯一性) 以前这个是可以不加的,现在必需加 namespace的值,规则的:映射文件XxxMapper.xml所在的包+domain类名+Mapper --> <mapper namespace="cn.wang.domain.ProductMapper"> <!-- select : 这里面写查询语句 id:sql语句的标识,在同一个namespace下不能重复 parameterType : 传入的参数类型(原本应该用的是全限定名,这里用的是别名) long:大Long _long:小long (具体的对应请参见文档) resultType : 返回的结果类型(每一条数据返回的对象类型) 自己的对象一定是全限定类名(这里写的是别名) --> <select id="findOne" parameterType="long" resultType="Product"> select * from product where id=#{id} </select> <!--别名不区分大小写--> <select id="findAll" resultType="product"> select * from product </select> <insert id="insert" parameterType="product" keyProperty="id" useGeneratedKeys="true"> 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="long"> UPDATE product set productName=#{productName} where id=#{id} </update> <delete id="delete" parameterType="long"> delete FROM product where id=#{id} </delete> </mapper>
5.最后进行测试
public class MybatisTest { private IProductDao productDao=new ProductDaoImpl(); @Test public void testFindOne(){ Product product = productDao.findOne(1L); System.out.println(product); } @Test public void testFindAll(){ List<Product> list = productDao.findAll(); for (Product product : list) { System.out.println(product); } } @Test public void testInsert(){ Product product = new Product(); product.setProductName("大金刚"); product.setDir_id(3L); product.setSalePrice(100.00); product.setSupplier("哈哈哈"); product.setBrand("哇咔咔"); product.setCutoff(0.66); product.setCostPrice(23.00); productDao.save(product); //获取新添加数据的主键,前提insert标签已经配置了那三个属性 System.out.println(product.getId()); } @Test public void testUpdate(){ Product product = productDao.findOne(1L); product.setProductName("大罗金仙"); productDao.update(product); } @Test public void testDelete(){ productDao.delete(1L); } }