(一)对象关系映射
对象关系映射是一种为了解决面向对象与关系型数据库之间存在的不匹配的现象的技术。
简单说ORM就是通过 描述对象和数据库之间映射的元数据,将java程序中的对象自动持久化到关系型数据库中。避免直接使用SQL语句对关系型数据库中的数据进行操作,减少代码编写量,提高产品质量。
因为java语言是面向对象的语言,我们使用的DB是关系型DB,JPA就是一个ORM的规范,hibernate就是ORM规范的一个实现非常完整的框架,myBits是对ORM实现半完整的框架
(二)JDBC、hibernate、MyBatis之间的关系
1、原生的JDBC
① 开发效率比价低下(因为需要写贾琏欲执事,需要自行获取并设置对象)
② 运行效率比较高,但前提是必须添加DB连接池和缓存,否则效率也是相对比较低下的
③ 重复性的代码比较多
2、hibernate
① 开发速度非常高,目前是所有ORM实现框架内速度最高的(因为其内部已经内置了CRUD)
② 运行速度比较低下(因为其底层自动生成SQL,需要考虑兼容各种DB、各种兼容问题导致其无法选择最优的方案)
3、myBatis
① 开发效率高于JDBC,低于hibernate
② 运行速度快,和原生的JDBC速度差不多(因为是自己写SQL,可以控制性能)
③ 上手简单且快
④ 不会自动创建表,需要自己创建表
(三)hello mybatis
1、创建一个普通的java项目
2、导包
- MyBatis的核心包
- MyBatis的依赖包
- 数据库的驱动包
注意:
因为java中所有操作数据库的框架底层都是JDBC,所以必须导入相对应的数据库驱动包
JDBC只是sun指定的规范,需要各大数据库厂商自行实现
普通java项目将jar拷贝之后需要手动导包==选中jar包文件夹–右键–add as library
3、创建表和domain
4、配置文件
注意:
所有的配置文件都应该在resources下,注意将文件变色–选中配置文件夹—右键
- jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mybatis
jdbc.username=root
jdbc.password=admin
- 主配置文件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">
<!--配置根,xml中必须有一个根-->
<configuration>
<!--引入外部的数据库配置信息-->
<properties resource="jdbc.properties"></properties>
<!--environments :多个环境,
一个环境就代表一个数据库的连接信息
default: 默认使用的环境(生成、测试环境的数据库),名字随意
-->
<environments default="development">
<environment id="development">
<!--事务管理类型 type="[JDBC/MANAGED]" MANAGED没有事务 -->
<transactionManager type="JDBC"/>
<!--配置连接池-->
<dataSource type="POOLED">
<!--四大金刚 以后集成会改为DBCP/C3P0-->
<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>
<!--注意需要引入sql的xml配置文件
注意:① 使用resource进行接收
② 不要使用全限定名,此处是路径
③ 路径是相对路径,不是绝对路径
-->
<mappers>
<mapper resource="cn/lzj/domain/_01_helloMyBatis/productMapper.xml"/>
</mappers>
</configuration>
- sql的映射文件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">
<!--namespace:命名空间,
因为以后会写很多sql,java代码需要精确的找到某一条sql,通过命名空间和sql的id
-->
<mapper namespace="cn.lzj.domain._01_helloMyBatis.ProductMapper">
<!--
id:这条sql的唯一名称
parameterType:参数类型
long: 大long _long:小long
resultType:返回的(每一条数据)结果类型 必须写全限定名
-->
<select id="findOne" parameterType="long" resultType="cn.lzj.domain._01_helloMyBatis.Product">
select * from product where id = #{id}
</select>
<select id="findAll" resultType="cn.lzj.domain._01_helloMyBatis.Product">
select * from product
</select>
</mapper>
(四)mybatis的CRUD
1、抽取获取session的工具类
public class MyBatisUtil {
private static SqlSessionFactory factory;
static {
try {
factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));
} catch (Exception e) { //注意此处不要使用IOException,否则会出现不报错,但运行无效果
e.printStackTrace();
}
}
public static SqlSession openSession(){
return factory.openSession();
}
}
2、添加数据
注意:数据库中的表格的引擎如果是MyIASM,则不需要提交事务,也能成功添加数据,但将引擎修改为INNODB,就需要进行事务的提交
INNODB引擎:支持事务,支持外键,安全
MyISAM引擎:不支持事务,不支持外键,操作数据速度快
核心代码:
<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>
3、删除数据
<delete id="delete" parameterType="long">
delete from product where id = #{id}
</delete>
4、修改数据
<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>
增删改都需要提交事务
(五)mybatis的细节处理
1、添加数据时,需要id
useGeneratedKeys:是否要返回id
keyColumn:数据库中的主键对应的列
keyProperty:domain中对应的主键属性
id返回到传过来的对象中
<insert id="save" parameterType="product" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
2、别名
在mybatis-config.xml内配置别名
别名不区别大小写
有配置顺序(如果配置错误会有提示)
<typeAliases>
<!--单独修改一个domain的别名-->
<!--<typeAlias type="cn.lzj.domain._01_helloMyBatis.Product" alias="Product"/>-->
<!--直接扫描整个domain,开发时常用,每个别名就是类名-->
<package name="cn.lzj.domain"/>
</typeAliases>
#和$之间的区别
"#"相当于?
"$"相当于字符串的拼接
① 要 求 必 须 传 对 象 , 因 为 要求必须传对象,因为 要求必须传对象,因为是获取的对象的属性(get属性)
② # 使用占位符,KaTeX parse error: Expected 'EOF', got '#' at position 29: …③例如:根据name获取数据,#̲可以获取,不可以获取,–>$需要进行字符串的拼接,加双引号
因为SQL的要求,?只能出现在where的条件内
3、列名与属性名不一致
解决数据库中的列名和domain中的属性名不一致
在productMapper.xml进行配置
<!--解决数据量列名和domain中的属性名不一致的问题-->
<resultMap id="productMapper" type="product">
<!--主键使用id,其他属性使用result-->
<id column="id" property="id"></id>
<!--
result:某一个属性的映射
column:列名(表中) property:属性名(对象中)
-->
<result column="dir_id" property="dirId"></result>
</resultMap>
4、常见异常现象
以为mybatis的配置信息比较复杂,所以需要注意的细节点比较多,以下列举一些通过mybatis获取数据出现的常见异常信息
- org.apache.ibatis.exceptions.PersistenceException:
The error may exist in /cn/lzj/domain/_01_helloMyBatis/productMapper.xml
路径配置错误:
原因<mappers> <mapper resource="cn/lzj/domain/_01_helloMyBatis/productMapper.xml"/> </mappers>
sql的xml配置文件在mybatis的主配置文件内的位置应该与resouces接收,并获取相对路径,而不是绝对路径
- Caused by: java.lang.ClassNotFoundException: Cannot find class: id
参数类型错误:
<select id="findOne" parameterType="long" resultType="cn.lzj.domain._01_helloMyBatis.Product">
select * from product where id = #{id}
</select>
原因:
sql语句的参数类型应该为参数值id的类型为long ,而不是id类型
- java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for cn.lzj.domain._01_helloMyBatis.ProductMapper.findOne
原因:
需要在mybatis的主配置文件内加载映射sql的xml文件,才能进行使用
(六)log4j日志框架
1、导包
2、log4j.properties
# 全局:你要打印的东西:只打印错误
log4j.rootLogger=ERROR, stdout
#log4j.rootLogger=NONE
#把左边包名需要修改为对应的包名
#局部要求 ERROR:错误 Warn:警告 Info:信息 Debug:调试 TRACE:详细 NONE:不显示日志信息
log4j.logger.cn.lzj=TRACE
#代表的是打印的位置
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#打印的格式(可以灵活地指定布局模式)
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#这里就是自定义的格式 %d:时间 %p:级别
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
3、测试
@Test
public void test() throws Exception{
//获取Logger对象的实例 导入的是org.apache.log4j.Logger;
Logger logger = Logger.getLogger(LogTest.class);
logger.trace("详细信息");
logger.debug("调试信息");
logger.info("普通的信息");
logger.warn("警告信息");
logger.error("错误信息");
}