一.Mybatis介绍
概念
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL
本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
背景
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation
迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
二.mybatis的入门案例
需求1: 根据id查询一个用户
掌握的内容: mybatis如何来使用.
1.准备环境
- mysql的jar ; mybatis的jar junit的jar , lombok.jar,日志
<dependencies>
<!-- mysql的jar -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!--mybatis的jar -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!-- junit的jar -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- lombok的jar -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<!-- 日志的jar -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.6</version>
</dependency>
</dependencies>
- 创建一个SqlSessionFactoryBuilder 对象 (工厂构建对象) 方法build (InputStream)
- Resources类,静态方法getResourcesAsStream(“加载核心配置文件SqlMapConfig.xml”) 得到一个InputStream流对象
- 使用build方法创建一个SqlSessionFacotory ,得到一个会话工厂对象
- 使用工厂对象调用openSession()方法获取一个SqlSession对象
- 使用SqlSession对象的查询方法 selectOne(“namespace的id”,实际传递的id值) 得到用户对象
- 关闭资源
- 编写核心配置文件SqlMapConfig.xml文件 (1配置数据库的环境 2.加载映射文件)
☆☆☆:
<?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="development">
<!-- 环境配置-->
<environment id="development">
<!--mybatis的事务管理使用JDBC -->
<transactionManager type="JDBC"/>
<!---数据源-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis01"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 加载映射文件-->
<mappers>
<!-- 引入指定的映射文件-->
<mapper resource="UserMapper.xml"></mapper>
</mappers>
- 编写映射文件 UserMapper.xml (编写SQL语句 )
<?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名称空间 作用区分不同模块下的的sql语句
-->
<mapper namespace="user">
<!-- 需求:根据id查询一个用户的信息
属性
id =该条sql语句的唯一标志 ,一会后台需要使用id值,来执行SQL,必须存在
parameterType 传入过来的参数类型 写的是类的全完全路径名
-->
<select id="findUserById" parameterType="java.lang.Integer" resultType="com.sen.pojo.User">
<!--
#{} 来传递参数,是一个占位符
如果是基本数据类型或者字符串String 值可以写任意值 #{任意值}
如果穿的是参数类型是pojo类型,值要传递pojo的属性值
-->
<!-- 根据id 查询sql语句-->
select * from user where id = #{id}
</select>
<!--
2.根据name模糊查询
如果返回值类型是List<User> resultType中 集合的泛型
-->
<select id="findUserByName" parameterType="java.lang.String" resultType="com.sen.pojo.User">
select * from user where username like #{name}
</select>
<!--
3.根据name模糊查询(版本2)
如果返回值类型是List<User> resultType中 集合的泛型
${} 字符串拼接方式传递参数
接受的参数类型如果是基本数据类型 只能写 value
-->
<select id="findUserByName2" parameterType="java.lang.String" resultType="com.sen.pojo.User">
select * from user where username like '%${value}%'
</select>
<!--
4.添加一个用户
直接传递一个User对象 (自动完成映射)
-->
<insert id="addUser" parameterType="com.sen.pojo.User">
<!--parameterType:如果参数类型是一个POJO对象,#{POJo的属性值}
private int id;
private String username;
private Date birthday;
private String sex;
private String address;
-->
insert into user values(null,#{username},#{birthday},#{sex},#{address})
</insert>
</mapper>
- 在测试类中进行测试 Demo1_Mybatis
@Test
public void test01() throws IOException {
//1.创建SqlSessionFactoryBuilder 对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//2.Resources调用getResourceAsStream(核心配置文件) 返回一个流
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//3.SqlSessionFactoryBuilder 对象有一个build方法(流) ,返回一个SqlSessionFactory
SqlSessionFactory sqlSessionFactory = builder.build(inputStream);
//4.通过SqlSessionFactory 的openSession方法获取到一个SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();//参数:true 自动提交事务/false 手动提交事务(默认值)
//这里注意 查询一般默认不写(false)
//5.通过SqlSession调用一个selectOne("namespace的id.sql语句的id值", 实际查询的用户的id值) 返回一个user对象
User user = sqlSession.selectOne("user.findUserById",10);
//6.打印对象
System.out.println(user);
//7.关闭资源
inputStream.close();
sqlSession.close();
}
三.使用MyBaits来完成Dao层的编写 (原始方式)
UserDao–UserDaoImpl
public interface UserDao {
//根据id查询
public User findUserById(int id);
//根据name模糊查询
public List<User> findUserByName(String name);
//添加用户
public void addUser(User user);
}
/**
* 添加用户:
* sqlSession.调用增删改查的方法 --- SqlSessionFactory
*/
public class UserDaoImpl implements UserDao {
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
//根据id查询user
public User findUserById(int id) {
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("user.findUserById", id);
return user;
}
//根据name模糊查询user
public List<User> findUserByName(String name) {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> list = sqlSession.selectList("user.findUserByName", name);
return list;
}
//添加用户
public void addUser(User user) {
SqlSession sqlSession = sqlSessionFactory.openSession(true);
sqlSession.insert("user.addUser",user);
}
}
测试类
//测试原始的Dao中的方法
public class UserDaoTest {
private UserDao dao = null;
@Before
public void init() throws IOException {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory = builder.build(inputStream);
//创建UserDao对象
dao = new UserDaoImpl(factory);
}
@Test
public void findUserByIdTest() throws IOException {
User user = dao.findUserById(1);
System.out.println(user);
}
@Test
public void findUserByNameTest() {
List<User> list = dao.findUserByName("张");
System.out.println(list);
}
@Test
public void addUserTest() {
User user = new User("柳岩",new Date(), "2","北京回龙观");
dao.addUser(user);
}
}
三.mybatis的动态代理方式开发dao (重点)
动态代理的注意事项
-
第一个特点是编写之后接口没有实现类,dao改名mapper (包名修改mapper 接口也要修改UserMapper)
-
UserMapper.xml映射文件中有四个规则
- namespace的名称为接口的完全路径名
- sql语句的id值必须和接口中方法的名称一致
- SQL语句的参数类型与接口方法中的参数类型一致
- SQL语句的返回值类型与接口方法的返回值类型一致 (集合写的是泛型)
图解:
- 之前的方法有改动
- sqlSession会话对象的方法更变为 getMapper(接口的字节码对象), 该方法返回的是接口的子类代理对象.
UserMapper接口–接口的测试类
public interface UserMapper {
public User findUserById(int id);
public List<User> findByName(String name);
public void insertUser(User user);
}
/**
* 之前获取工厂对象方式和以前一致,从sqlSession调用方法开始不一致
*
*/
public class UserMapperTest {
private SqlSessionFactory factory = null;
@Before
public void init() throws IOException {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
factory = builder.build(inputStream);
}
@Test
public void findUserById() {
SqlSession sqlSession = factory.openSession();
//通过sqlSession的getMapper方法获取到接口的子类代理对象 : 动态代理模式
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.findUserById(1);
System.out.println(user);
}
@Test
public void findByName() {
SqlSession sqlSession = factory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> list = mapper.findByName("张");
for (User user : list) {
System.out.println(user);
}
}
@Test
public void insertUser() {
SqlSession sqlSession = factory.openSession(true);
User user = new User("柳传志",new Date(), "1","昌平");
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.insertUser(user);
}
}
个人注意事项:
-
java.lang.Integer
-
SqlMapConfig
- <!- - 引入指定的映射文件-- >
< mapper resource=“UserMapper.xml”>< /mapper> - < property name=“url” value=“jdbc:mysql:///mybatis01”/>
- <!- - 引入指定的映射文件-- >
-
mybatis的动态代理方式开发dao
- UserMapper.xml
- < mapper namespace=“com.sen.mapper.UserMapper”>
- ${} 字符串拼接方式传递参数
接受的参数类型如果是基本数据类型 只能写 value - 如果返回值类型是List resultType中 集合的泛型
- resultType=“com.sen.pojo.User”
- 模糊查询
- select * from user where username like ‘%${value}%’
- UserMapper.xml
jdbc问题总结如下: 1浪费资源, 2存在硬代码 3
1、 数据库连接创建、释放频繁造成系统资源浪费,从而影响系统性能。如果使用数据库连接池可解决此问题。
2、 Sql语句在代码中硬编码,造成代码不易维护,实际应用中sql变化的可能较大,sql变动需要改变java代码。
3、 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
4、 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。