Mybatis第一课-牛

Mybatis第一天

 1 课程计划

JAVAEE开发的三剑客:三大框架SSM

Mybatis封装jdbc访问代码的一个框架      (hibernate)    ORM

Spring MVC:用来封装servlet编程的一个框架(struts2

Spring:体系整合框架,其他框架的粘合剂;

什么是框架

框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法; 另一种定义认为,框架是可被应用开发者定制的应用骨架。是用框架可以提高程序复用性和系统的可扩充性,以缩短大型应用软件系统的开发周期,提高开发质量。

框架的优点(总结)

1.灵活可配置:将程序中写死的代码(硬编码)可以写到配置文件中 解耦

2.代码复用性高:将程序中反复要写的代码(套路代码)进行抽取封装,提高代码的复用性

3.简化开发:框架将底层复杂的细节进行了封装,并提供了方便调用的API,使得开发人员将工作的重点转移到实际业务中,大大提高了项目的开发效率

第一天:

1、mybatis的介绍

2、Mybatis的入门

a) 使用jdbc操作数据库存在的问题

b) Mybatis的架构

c) Mybatis的入门程序

3、Mybatis的开发流程

4、dao开发

实现增删改查

第二天:

1、抽取DAO接口

2、通过反射动态加载类

3Mapper动态代理

第三天:

1、输出映射

2、动态sql

3、设计表及表关系的存储 

2 MyBatis介绍

MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。 MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。

Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

使用jdbc编程问题总结

3.1 创建mysql数据库

先导入创建数据库的sql脚本导入到数据库中。

 

 

3.2 创建工程

开发环境:

eclipse mars

Jdk1.7

 

1、创建一个java工程。

2、导入jar包。此时需要mysql 的数据库驱动。

 

3.3 jdbc编程步骤:

1、 加载数据库驱动

2、 创建并获取数据库链接

3、 创建jdbc statement对象

4、 设置sql语句

5、 设置sql语句中的参数(使用preparedStatement)

6、 通过statement执行sql并获取结果

7、 sql执行结果进行解析处理

8、 释放资源(resultSetpreparedstatementconnection)

 

3.4 jdbc程序

public static void main(String[] args) {

Connection connection = null;

PreparedStatement preparedStatement = null;

ResultSet resultSet = null;

try {

//加载数据库驱动

Class.forName("com.mysql.jdbc.Driver");

//通过驱动管理类获取数据库链接

connection =  DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "root");

//定义sql语句 ?表示占位符

String sql = "select * from user where username = ?";

//获取预处理statement

preparedStatement = connection.prepareStatement(sql);

//设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值

preparedStatement.setString(1, "");

//向数据库发出sql执行查询,查询出结果集

resultSet =  preparedStatement.executeQuery();

//遍历查询结果集

while(resultSet.next()){

System.out.println(resultSet.getString("id")+"  "+resultSet.getString("username"));

}

} catch (Exception e) {

e.printStackTrace();

}finally{

//释放资源

if(resultSet!=null){

try {

resultSet.close();

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

if(preparedStatement!=null){

try {

preparedStatement.close();

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

if(connection!=null){

try {

connection.close();

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

 

上边使用jdbc的原始方法(未经封装)实现了查询数据库表记录的操作。

 

3.5 jdbc问题总结如下:

1、 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。

2、 Sql语句在代码中硬编码,造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。

3、 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。

4、 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。

 

补充:持久层框架总结

Jdbc,DBUtil,Hibernate,Mybatis

mybatis解决了前面这些框架的痛点,来说一下痛点

jdbc

优点:原生,速度快

缺点:使用不方面,先得getset

DBUtils

优点:只要数据库名字和实体类名字,一致,就自动设置属性,底层用的反射

缺点:sql语句写在类中,改sql就得改代码,硬编码

Hibernate

优点:hql语句,需要把sql写到文件里面,提供了一种对象关系映射,用起来更方便

缺点:底层运行的效率不太高

 

mybatis就解决了前面的所有问题

优点简述:

在原生api的基础上,进行的进一步封装,开发使用起来,更方便,效率更高。

隐藏了底层复杂的实现过程,使得不用关注底层,只需关注业务逻辑的开发。

通过使用配置文件或者注解的方式,使应用程序更加的灵活。

 

 

Mybatis架构

 

Mybatis流程图

 

 

1、 mybatis配置

SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。

mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。

2、 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂(单例)

3、 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。

4、 mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。

5、 Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sqlid即是Mapped statementid

6、 Mapped Statementsql执行输入参数进行定义,包括HashMap、基本类型、pojoExecutor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。

7、 Mapped Statementsql执行输出结果进行定义,包括HashMap、基本类型、pojoExecutor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

 

 

 

Mybatis入门程序

6.1 mybatis下载

mybaits的代码由github.com管理,地址:https://github.com/mybatis/mybatis-3/releases

 

 

mybatis-3.2.7.jar----mybatis的核心包

lib----mybatis的依赖包

mybatis-3.2.7.pdf----mybatis使用手册

 

 

6.2 需求

实现以下功能:

根据用户id查询一个用户信息

查询所有用户

添加用户

更新用户

删除用户

 

6.3 工程搭建

6.3.1 第一步:创建java工程

使用eclipse创建java工程,jdk使用1.8

6.3.2 第二步:加入jar

加入mybatis核心包、依赖包、数据驱动包。

 

6.3.3 第三步:SqlMapConfig.xml

classpath下创建SqlMapConfig.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>

<!-- spring整合后 environments配置将废除-->

<environments default="development">

<environment id="development">

<!-- 使用jdbc事务管理-->

<transactionManager type="JDBC" />

<!-- 数据库连接池-->

<dataSource type="POOLED">

<property name="driver" value="com.mysql.jdbc.Driver" />

<property name="url" value="jdbc:mysql://localhost:3306/ssm?characterEncoding=utf-8" />

<property name="username" value="root" />

<property name="password" value="123" />

</dataSource>

</environment>

</environments>

</configuration>

 

SqlMapConfig.xmlmybatis核心配置文件,上边文件的配置内容为数据源、事务管理。

6.3.4 第四步:实体类

实体类作为mybatis进行sql映射使用,实体类通常与数据库表对应,User.java如下:

 

Public class User {

private Long id;

private String name;// 用户姓名

private int age;// 年龄

get/set……

6.3.5 第五步:sql映射文件

classpath下的sqlmap目录下创建sql映射文件User.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="User">

<select id="findAll" resultType="cn.edu360.mybatis.day1.User">

</select>

</mapper>

 

namespace 命名空间,用于隔离sql语句,后面会讲另一层非常重要的作用。

6.3.6 第七步:在核心配置文件中加载sql映射文件

mybatis框架需要加载映射文件,将User.xml添加在SqlMapConfig.xml,如下:

 

<!-- 核心配置文件可以组装我们的mapper映射文件 -->

<mappers>

<mapper resource="UserMapper.xml" />

</mappers>

 

6.3.7 执行测试

public class HelloWorld {

public static void main(String[] args) throws IOException {

// 配置文件(1,核心配置文件,用于组装映射配置文件,2映射配置文件,用于实体类和数据库表的对应关系)

InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");

// sqlSessionFactory 工厂,产生sqlSession

// sqlSessionFactory 相当于jdbc中的DriverManager 连接池

// sqlSession 相当于jdbc中的Connection对象

// sqlSessionFactoryBuilder 构建器

SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

// 通过构建器的build 方法 获取sqlSessionFactory

SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);

 

// 通过sqlSessionFactoryopenSession方法,获取到了一个sqlSession

SqlSession sqlSession = null;

try {

sqlSession = sqlSessionFactory.openSession();

// 执行sql

List<User> list = sqlSession.selectList("User.findAll");

for (User u : list) {

System.out.println(u.getName());

}

} finally {

// 释放资源

if (sqlSession != null)

sqlSession.close();

}

}

}

Mybatis开发流程

以小案例为示例,说明mybatis的开发流程

 1,创建project,导入jar包(驱动连接包,mybatis核心包,mybatis依赖包) 

2,创建核心的配置文件sqlMapConfig.xml,设置一个JDBC的连接,然后修改我们的连接池配置(数据库驱动名,数据库的连接url,数据库用户名,数据库用户密码)

com.mysql.jdbc.Driver jdbc:mysql://localhost:3306/ssm?characterEncoding=utf-8

 3,创建映射配置文件UserMapper.xml,mapper标签需要命名空间namespace唯一,我们可以再这个标签下面编写我们的增删改查sql语句

 4,在核心配置文件里面,把编写好的映射配置文件添加进去,<mappers>(组装)

 5,新建一个程序,调用sqlSessionFactoryBuilder的 build方法,获得一个sqlSessionFactory对象。

 6,通过sqlSessionFactory的openSession()方法获取sqlSession

 7,通过sqlSession执行我们的增删改查业务逻辑

 8,解析查询数据

 9,调用close方法关闭连接。

注意:这里是把连接返回给给连接池,不是真正的关闭连接。

 

mybatis开发优点总结:

1, sql语句和代码分离,解决了硬编码问题,实现了解耦

2, 使用mybatis自带的连接池,还可接入第三方连接池

3, 自动实现了数据库表字段和实体类属性的映射,使用方便

4, 封装了查询接口,隐藏了底层实现,使开发人员更专注于业务逻辑代码的开发

 

DAO开发

8.1 需求

实现增删改案例,使用JUnit单元测试对代码进行测试,并对套路代码进行封装。

 

JUnit单元测试要求:

1, 方法必须是public

2, 返回值类型必须是void

3, 方法必须没有参数

4, 可以抛出异常,但是不主动捕获异常

5, 方法需要加上@Test注解

 

 

8.2 创建DAO

创建DAO,并加载sqlSessionFactory

public class UserDao {

 

private static SqlSessionFactory sqlSessionFactory = null;

// 在構造方法之前执行,在类加载的时候执行

static {

// 创建sqlSessionFactory

try {

sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml"));

} catch (IOException e) {

// 执行一些异常处理

// log.log(e)

e.printStackTrace();

}

}

}

8.3 添加用户

8.3.1 映射文件:

SqlMapConfig.xml中添加:

<!-- 添加用户 -->

<insert id="save1" parameterType="cn.edu360.mybatis.day1.User">

INSERT INTO t_user (id,name) VALUES  (null,#{name})

</insert>

8.3.2 业务逻辑:

public void save(User user){

// 调用mybatisapi进行操作

SqlSession sqlSession = sqlSessionFactory.openSession();

// insert 方法 传递了一个user对象,这个user对象封装了用户数据

int count = sqlSession.insert("User.save1", user);

// 解析返回结果

System.out.println(count);

// 执行修改操作,必须提交事务 (save,udpate,delete

// 提交事务

sqlSession.commit();

// 释放资源

sqlSession.close();

}

8.3.3 测试方法:

@Test

public void testSave() {

// 调用dao里面的save方法

UserDao dao = new UserDao();

// 创建实体类

User u = new User();

// 赋值

u.setName("凤姐");

dao.save(u);

}

8.4 删除用户

8.4.1 映射文件:

<!-- 删除用户 -->

<delete id="deleteById" parameterType="long">

DELETE FROM t_user where id = #{id}

</delete>

8.4.2 业务逻辑:

public void deleteById(Long id) {

// 调用mybatisapi进行操作

SqlSession sqlSession = sqlSessionFactory.openSession();

 

// insert 方法 传递了一个user对象,这个user对象封装了用户数据

int count = sqlSession.delete("User.deleteById", id);

// 解析返回结果

System.out.println(count);

// 提交事务

sqlSession.commit();

// 释放资源

sqlSession.close();

}

8.4.3 测试程序:

@Test

public void testDeleteById() {

// 创建dao

UserDao dao = new UserDao();

// 调用方法

dao.deleteById(14L);

}

8.5 根据id修改用户信息

8.5.1 映射文件:

<update id="update" parameterType="cn.edu360.mybatis.day1.User">

UPDATE t_user SET name=#{name}, age = #{age} WHERE id = #{id}

</update>

8.5.2 业务逻辑:

public void update(User user) {

// 调用mybatisapi进行操作

SqlSession sqlSession = sqlSessionFactory.openSession();

sqlSession.update("User.update", user);

// 提交事务

sqlSession.commit();

// 释放资源

sqlSession.close();

}

8.5.3 测试程序:

private UserDao dao = null;

@Before

public void init(){

dao = new UserDao();

}

@Test

public void testUdpate() {

// 创建实体对象

User u = new User();

// 赋值

u.setName("凤姐万人迷");

u.setAge(18);

u.setId(15L);

// 调用方法

dao.update(u);

}

8.6 根据ID查询用户信息

8.6.1 映射文件:

<!-- 自定义条件查询用户列表 -->

<select id="getById" parameterType="long" 

resultType="cn.edu360.mybatis.day1.User">

   select * from t_user where id = #{id} 

</select>

 

8.6.2 业务逻辑:

public User getById(Long id){

// 调用mybatisapi进行操作

SqlSession sqlSession = sqlSessionFactory.openSession();

// 执行查询

User user = sqlSession.selectOne("User.getById", id);

// 释放资源

sqlSession.close();

// 返回查询结果

return user;

}

8.6.3 测试程序:

@Test

public void testGetById(){

dao.getById(15L);

}

 

8.7 查询所有用户信息

8.7.1 映射文件:

<select id="findAll" resultType="cn.edu360.mybatis.day1.User">

select * from t_user

</select>

8.7.2 业务逻辑:

public List<User> findAll(){

// 调用mybatisapi进行操作

SqlSession sqlSession = sqlSessionFactory.openSession();

// 执行查询

List<User> user =  sqlSession.selectList("User.findByName");

for(User u:user){

System.out.println(u);

}

// 释放资源

sqlSession.close();

// 返回查询结果

return user;

}

8.7.3  测试程序:

@Test

public void testFindAll(){

dao.FindAll();

}

 

8.8 根据name查询一条用户信息

8.8.1 映射文件:

<select id="getByName" parameterType="String" resultType="cn.edu360.mybatis.day1.User">

SELECT * FROM t_user where name = #{name}

</select>

8.8.2 业务逻辑:

public User getByName(String name){

// 调用mybatisapi进行操作

SqlSession sqlSession = sqlSessionFactory.openSession();

// 执行查询

User user =  sqlSession.selectOne("User.getByName", name);

System.out.println("name="+user.getName());

// 释放资源

sqlSession.close();

// 返回查询结果

return user;

}

8.8.3  测试程序:

@Test

public void testGetByName(){

dao.getByName(“凤姐”);

}

8.9 根据name模糊查询用户信息

8.9.1 映射文件:

<select id="findByName" parameterType="String" resultType="cn.edu360.mybatis.day1.User">

SELECT * FROM t_user WHERE name like '%${value}%'

</select>

parameterType:定义输入到sql中的映射类型,${value}表示使用参数将${value}替换,做字符串的拼接。

注意:如果是取简单数量类型的参数,括号中的值必须为value

resultType定义结果映射类型。

 

模糊匹配如果写name like #{name} , 需要在测试代码里面进行模糊匹配,否则和name = #{name} 查询结果一样

List<User> uList = dao.findByName("%凤姐%");

配置文件中还可以写成:

SELECT * FROM t_user where name like "%"#{name}"%"

 

 

8.9.2 业务逻辑:

public User findByName(String name){

// 调用mybatisapi进行操作

SqlSession sqlSession = sqlSessionFactory.openSession();

// 执行查询

List<User> user =  sqlSession.selectList("User.findByName", name);

System.out.println("name="+user.size());

// 释放资源

sqlSession.close();

// 返回查询结果

return null;

}

8.9.3  测试程序:

@Test

public void testFindByName(){

dao.FindByName(“凤姐”);

}

 

 

8.10 小结

8.10.1 #{}${}

#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。

 

${}表示拼接sql串,通过${}可以parameterType 传入的内容拼接在sql且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value

 

 

8.10.2 parameterTyperesultType

parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中。

resultType:指定输出结果类型,mybatissql查询结果的一行记录映射为resultType指定类型的对象。

 

8.10.3 selectOneselectList

 

selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常:

org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3

at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70)

 

selectList可以查询一条或多条记录。

 

8.11 Mybatis解决jdbc编程的问题

1、 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。

解决:SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。

2、 Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。

解决:Sql语句配置在XXXXmapper.xml文件中与java代码分离。

3、 sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。

解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。

4、 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。

解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。

 

8.12 SqlSession的使用范围

SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。

通过SqlSessionFactory创建SqlSession,而SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。

 

8.12.1 SqlSessionFactoryBuilder

SqlSessionFactoryBuilder用于创建SqlSessionFacotySqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory生产,所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。

 

8.12.2 SqlSessionFactory

SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory

 

8.12.3 SqlSession

SqlSession是一个面向用户的接口, sqlSession中定义了数据库操作方法。

每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。

打开一个 SqlSession;使用完毕就要关闭它。通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。如下:

SqlSession session = sqlSessionFactory.openSession();

try {

   // do work

} finally {

   session.close();

}

 

 

SqlMapConfig.xml配置文件

9.1 配置内容

SqlMapConfig.xml中配置的内容和顺序如下:

 

properties(属性)

settings(全局配置参数)

typeAliases(类型别名)

typeHandlers(类型处理器)

objectFactory(对象工厂)

plugins(插件)

environments(环境集合属性对象)

environment(环境子属性对象)

transactionManager(事务管理)

dataSource(数据源)

mappers(映射器)

 

 

 

补充: DTD约束的本地文件加载配置

1、eclipse中点击

 

 

2

 

3、添加dtd约束文件

 

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值