第一个demo快速实现实现
准备一个domain(Product)(与数据库的字段对应)
package cn.itsource.domain;public class Product { private Long id; private String productName; //产品名称 private Double salePrice; //价格 private String supplier; //供应商 private String brand; //品牌 private Double cutoff; //折扣 private Double costPrice; //售价 // private Long dir_id; //类型id //这个名称和表中的名称对应不上了 private Long dir_id; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getProductName() { return productName; } public void setProductName(String productName) { this.productName = productName; } public Double getSalePrice() { return salePrice; } public void setSalePrice(Double salePrice) { this.salePrice = salePrice; } public String getSupplier() { return supplier; } public void setSupplier(String supplier) { this.supplier = supplier; } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public Double getCutoff() { return cutoff; } public void setCutoff(Double cutoff) { this.cutoff = cutoff; } public Double getCostPrice() { return costPrice; } public void setCostPrice(Double costPrice) { this.costPrice = costPrice; } public Long getDir_id() { return dir_id; } public void setDir_id(Long dir_id) { this.dir_id = dir_id; } @Override public String toString() { return "Product{" + "id=" + id + ", productName='" + productName + '\'' + ", salePrice=" + salePrice + ", supplier='" + supplier + '\'' + ", brand='" + brand + '\'' + ", cutoff=" + cutoff + ", costPrice=" + costPrice + ", dir_Id=" + dir_id + '}'; }}xml映射文件ProductMapper.xml
<!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.itsource.dao.ProductMapper"> <!-- select : 这里面写查询语句 id:用来确定这条sql语句的唯一 以后我们确定唯一,也就是找sql语句 : namespace +.+ id 例: cn.itsource.mybatis.day1._1_hello.ProductMapper.get parameterType : 传入的参数类型 long:大Long _long:小long (具体的对应请参见文档) resultType : 结果类型(第一条数据返回的对象类型) 自己的对象一定是全限定类名 --> <select id="getOne" parameterType="ProductQuery" resultType="Product"> select * from product where productName = ${productName} </select> <select id="queryOne" parameterType="ProductQuery" resultType="Product"> select * from product where id = #{id} </select> <select id="queryAll" resultType="cn.itsource.domain.Product"> select * from product </select> <insert id="save" parameterType="cn.itsource.domain.Product"> 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="cn.itsource.domain.Product"> update product set productName = #{productName},dir_id=#{dir_id},salePrice=#{salePrice},supplier=#{supplier},brand=#{brand},cutoff=#{cutoff},costPrice=#{costPrice} where id = #{id} </update> <delete id="delete" parameterType="long"> delete from product where id = #{id} </delete></mapper>这里对获取SqlSession对象做了一个抽取
package cn.itsource.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;// 获取SqlSession的工具类public class SqlSessionUtils {// INSTANCE; private static SqlSessionFactory factory; static { try { factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml")); }catch (Exception e){ e.printStackTrace(); } } public static SqlSession creatSqlSession(){ return factory.openSession(); }}定义我们进行CRUD的接口IProductDao和ProductDaoimpl
package cn.itsource.dao;import cn.itsource.domain.Product;import cn.itsource.query.ProductQuery;import java.util.List;public interface IProductDao { void save(Product product); void delete(Long id); void update(Product product); Product queryOne(Long id); Product getOne(ProductQuery query); List<Product> queryAll();}
package cn.itsource.dao.impl;import cn.itsource.dao.IProductDao;import cn.itsource.domain.Product;import cn.itsource.query.ProductQuery;import cn.itsource.util.SqlSessionUtils;import org.apache.ibatis.session.SqlSession;import java.util.List;public class ProductDaoImpl implements IProductDao { private static String INSTANCE = "cn.itsource.dao.ProductMapper."; @Override public void save(Product product) { SqlSession sqlSession = null; try { sqlSession = SqlSessionUtils.creatSqlSession();// 数据库的持久化操作 sqlSession.insert(INSTANCE+"save",product);//拼接出来就是cn.itsource.dao.ProductMapper.save,注意这里一定要与IProductDao的方法名和映射文件的id的属性值完全对应上// 添加事务 sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); } finally { sqlSession.close(); } } @Override public void delete(Long id) { SqlSession sqlSession = null; try { sqlSession = SqlSessionUtils.creatSqlSession(); sqlSession.delete(INSTANCE+"delete",id); sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); } finally { sqlSession.close(); } } @Override public void update(Product product) { SqlSession sqlSession = null; try { sqlSession = SqlSessionUtils.creatSqlSession(); sqlSession.update(INSTANCE+"update",product); sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); } finally { sqlSession.close(); } } @Override public Product queryOne(Long id) { SqlSession sqlSession = null; try { sqlSession = SqlSessionUtils.creatSqlSession(); Product product = sqlSession.selectOne(INSTANCE+"queryOne", id); return product; } catch (Exception e) { e.printStackTrace(); } finally { sqlSession.close(); } return null; } @Override public List<Product> queryAll() { SqlSession sqlSession = null; try { sqlSession = SqlSessionUtils.creatSqlSession(); List<Product> list = sqlSession.selectList(INSTANCE + "queryAll"); return list; } catch (Exception e) { e.printStackTrace(); } finally { sqlSession.close(); } return null; } @Override public Product getOne(ProductQuery query) { SqlSession sqlSession = null; try { sqlSession = SqlSessionUtils.creatSqlSession(); Product product = sqlSession.selectOne(INSTANCE+"getOne", query); return product; } catch (Exception e) { e.printStackTrace(); } finally { sqlSession.close(); } return null; }}配置mybatis的核心配置文件(mybatis-config.xml)和 jdbc.properties文件mybatis核心配置文件
<?xml version="1.0" encoding="UTF-8" ?><!--mybatis的xml配置文件的约束--><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><!--配置文件的一个跟--><configuration> <!--引入连接数据库的四个配置--> <properties resource="jdbc.properties"></properties> <!--配置别名--> <typeAliases> <!-- 单个配置:练习 --> <!--<typeAlias type="cn.itsource.mybatis.a_crud.Dept" alias="Dept" />--> <!-- 包的配置:项目,添加了包之后,类名就是别名,这个配置之后domain包下面的所有类的别名都是它的类名,在映射文件里就不用写它的完全限定名了,直接写类名就可以了 --> <package name="cn.itsource.domain" /> <package name="cn.itsource.query" /> </typeAliases> <environments default="development"> <!--配置一个数据库的环境,还可以配置多个数据库的环境--> <environment id="development"> <!--事务管理器类型--> <!--在 MyBatis 中有两种事务管理器类型(也就是 type=”[JDBC|MANAGED]”)--> <!--JDBC – 这个配置直接简单使用了JDBC 的提交和回滚设置。它依赖于从数据源得 到的连接来管理事务范围。 MANAGED – 这个配置几乎没做什么。它从来不提交或回滚一个连接--> <transactionManager type="JDBC"/> <!--连接池:dpcp,c3p0,阿里的连接池--> <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> <!--引入写SQL的xml映射配置文件,这里的路径必须是映射文件的完全限定名的路径--> <mapper resource="cn/itsource/dao/ProductMapper.xml"/> <mapper resource="cn/itsource/dao/EmployeeMapper.xml"/> </mappers></configuration>
jdbc.properties文件
jdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql:///mybatisjdbc.username=rootjdbc.password=123456MybatisTest类
public class ProductTest1 { IProductDao productDao = new ProductDaoImpl();
@Test public void testSave() throws Exception{ Product product = new Product();// product.setId(10L);//数据库id自动递增,自动生成 product.setBrand("罗技"); product.setCostPrice(66.00); product.setCutoff(0.5); product.setId(2L); product.setProductName("鼠标"); product.setSalePrice(60.00); product.setSupplier("成都供应商");
productDao.save(product); }}本人对mybatis的一些认识和它的一些细节
- Mybatis是什么:MyBatis是一个ORM的数据库持久化框架
Mybatis是一个支撑框架,它以映射sql语句orm方式来数据库持久化操作.
数据持久化就是将内存中的数据保存到数据库里面,分为磁盘持久化和数据库持久化
缺点,SQL语句写在Java代码里面,修改了SQL语句就必须要修改代码 - Mybatis和JPA和JDBC的区别
a) Mybatis和JPA都是ORM映射框架,开发效率高,运行速度慢,
b) JDBC的开发效率慢,运行速度快,写很多重复代码
- ORM(对象关系映射):为了解决面向对象与关系型数据库存在互不匹配的技术
a) ORM操作数据库的两种方式
i. Mybatis实现方式(SQL操作方式):将SQL语句写到配置文件里面
ii. 直接映射的是对象实体和数据库关系映射,不用写SQL,框架自动生成(JPA,hibernate方式)
iii.
补充JPA,Hibernate,SpringDataJPA的关系
jpa:完整orm映射规范
hibernate:是整orm映射规范的一种实现.
DataJpa:对jpa的操作进行封装,让我们使用更加简单.
- Mybatis的简单入门实现
a) 准备mybatis的jar包和数据库的驱动包
i. 准备domain,dao层里面定义xml映射文件(注意映射文件与实体类的命名方式)
- Xml映射文件里面的属性认识
a) id:表示定位到mapper里面哪一个方法执行这条SQL,namespace定位到指定的一个mapper,parameterType表示传入的参数类型,resultType表示返回的结果值类型
ii. 核心对象:SqlSessionFactory的获取
- 准备mybatis-config.xml配置文件
<configuration>
<!-- 环境们 (很多环境的意思)
default:默认使用哪一个环境(必需对应一个环境的id)
-->
<environments default="development">
<!--
一个环境 id:为这个环境取唯一一个id名称
-->
<environment id="development">
<!--
事务管理 type:JDBC(支持事务)/MANAGED(什么都不做)
-->
<transactionManager type="JDBC" />
<!-- 数据源, 连接池 type(POOLED):MyBatis自带的连接池 -->
<dataSource type="POOLED">
<!-- 连接数据库的参数 -->
<property name="driver" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}"/>
</dataSource>
</environment>
</environments>
<!-- 这个mappers代表的是相应的ORM映射文件 -->
<mappers>
<mapper resource="cn/itsource/dao/ProductMapper.xml" />
</mappers>
</configuration>
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql:///test3306
db.username=root
db.password=admin
抽取myBatis的工具类(单例),减少代码书写 package cn.itsource.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; // 获取SqlSession的工具类 public class SqlSessionUtils { // INSTANCE; private static SqlSessionFactory factory; static { try { factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml")); }catch (Exception e){ e.printStackTrace(); } } public static SqlSession creatSqlSession(){ return factory.openSession(); } }
- Mybatis运行时的日志
mybatis中是使用日志来显示sql的在资源根目录创建一个log4j.properties
a)
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 [%c] - %m%n
注意:在上面的标红部分是我们需要修改的,它大概表示为当前会打印哪些位置下面文件的日志。
cn.itsource:一定要根据自己的包名情况进行修改
如果配置成功,那么在MyBatis运行操作数据时就可以看到相应的日志了。
- $和#的区别
a) #仅仅是一个占位符,相当于我们之前使用的“?”,最终通过preparetStatment预编译来设置参数,不会存在SQL注入问题,而$只是进行一个拼接
b) 或取值的区别
i. $不能获取getter的值只能从对象中获取值,而#可以,如果要使用$时就定义一个query来解决$不能获取getter值的问题
ii. 如果说是用$时,Id的时候是不用加“”,如果是字符串的时候就要加“”。
- 完全限定名别名问题(别名是完全不区分大小写的)
a)
在mybatis配置文件中去自定义别名
<typeAliases>
<typeAlias type=”完全限定名” alias=”别名”></typeAlias>
<package name = “cn.itsource.domian”/>为domain下面所有的类取别名,别名都是他的类名
</typeAliases>
- 获取刚刚添加到数据库的Id的问题
<!--
parameterType:需要传入我们的对象
useGeneratedKeys: 是否需要主键
keyColumn:主键所在的列
keyProperty:对象中的属性(代表主键的那个属性)
-->
<insert id="save" parameterType="cn.itsource.domain.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>
- Mybatis里面常用的动态SQL
a) foreEach,where,if
批量删除和批量添加
b)
批量添加:
<!--
批量添加
insert into employee (name,age,sex) values
("小小良",45,false),("大二良",45,true)
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>
c)
批量删除:
<!--
批量删除:DELETE FROM employee WHERE id in (?,?,?,...)
传 : List<Long> ids
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>
d)
动态修改:
<!--
动态修改:只修改有值的数据
-->
<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>