您的位置:首页 > 运维架构 > Apache

myBatis入门学习_上

2018-01-06 21:13 232 查看

MyBatis 百度百科介绍

MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。

iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)

下载地址

点我去下载地址

推荐下载版本 mybatis-3.1.1-bundle.zip

下载完成后,拷贝所有jar包到工程里面



环境搭建

创建一个数据库……….自己创建,

导入数据,复制sql,执行一下就行

/*
Navicat MySQL Data Transfer

Source Server         : connection
Source Server Version : 50715
Source Host           : localhost:3306
Source Database       : mybatis

Target Server Type    : MYSQL
Target Server Version : 50715
File Encoding         : 65001

Date: 2016-12-01 22:40:43
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for items
-- ----------------------------
DROP TABLE IF EXISTS `items`;
CREATE TABLE `items` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL COMMENT '商品名称',
`price` float(10,1) NOT NULL COMMENT '商品定价',
`detail` text COMMENT '商品描述',
`pic` varchar(64) DEFAULT NULL COMMENT '商品图片',
`createtime` datetime NOT NULL COMMENT '生产日期',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of items
-- ----------------------------
INSERT INTO `items` VALUES ('1', '台式机', '3000.0', '该电脑质量非常好!!!!', null, '2015-02-03 13:22:53');
INSERT INTO `items` VALUES ('2', '笔记本', '6000.0', '笔记本性能好,质量好!!!!!', null, '2015-02-09 13:22:57');
INSERT INTO `items` VALUES ('3', '背包', '200.0', '名牌背包,容量大质量好!!!!', null, '2015-02-06 13:23:02');

-- ----------------------------
-- Table structure for orderdetail
-- ----------------------------
DROP TABLE IF EXISTS `orderdetail`;
CREATE TABLE `orderdetail` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`orders_id` int(11) NOT NULL COMMENT '订单id',
`items_id` int(11) NOT NULL COMMENT '商品id',
`items_num` int(11) DEFAULT NULL COMMENT '商品购买数量',
PRIMARY KEY (`id`),
KEY `FK_orderdetail_1` (`orders_id`),
KEY `FK_orderdetail_2` (`items_id`),
CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of orderdetail
-- ----------------------------
INSERT INTO `orderdetail` VALUES ('1', '3', '1', '1');
INSERT INTO `orderdetail` VALUES ('2', '3', '2', '3');
INSERT INTO `orderdetail` VALUES ('3', '4', '3', '4');
INSERT INTO `orderdetail` VALUES ('4', '4', '2', '3');

-- ----------------------------
-- Table structure for orders
-- ----------------------------
DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '下单用户id',
`number` varchar(32) NOT NULL COMMENT '订单号',
`createtime` datetime NOT NULL COMMENT '创建订单时间',
`note` varchar(100) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`),
KEY `FK_orders_1` (`user_id`),
CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of orders
-- ----------------------------
INSERT INTO `orders` VALUES ('3', '1', '1000010', '2015-02-04 13:22:35', null);
INSERT INTO `orders` VALUES ('4', '1', '1000011', '2015-02-03 13:22:41', null);
INSERT INTO `orders` VALUES ('5', '10', '1000012', '2015-02-12 16:13:23', null);

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` date DEFAULT NULL COMMENT '生日',
`sex` char(1) DEFAULT NULL COMMENT '性别',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', '王五', null, '2', null);
INSERT INTO `user` VALUES ('10', '张三', '2014-07-10', '1', '北京市');
INSERT INTO `user` VALUES ('16', '张小明', null, '1', '河南郑州');
INSERT INTO `user` VALUES ('22', '陈小明', null, '1', '河南郑州');
INSERT INTO `user` VALUES ('24', '张三丰', null, '1', '河南郑州');
INSERT INTO `user` VALUES ('25', '陈小明', null, '1', '河南郑州');
INSERT INTO `user` VALUES ('26', '王五', null, null, null);


搭建完数据库环境后,然后开始搭myBatis所需的配置

创建pojo类

package cn.mybatis.pojo;

import java.util.Date;
/**
*
* @title User.java
* <p>description:用户表映射的PO类</p>
* <p>company: www.itheima.com</p>
* @author ljh
* @version 1.0
*/
public class User {
private Integer id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址

public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address="
+ address + "]";
}

}


在src同级目录下创建config文件夹

创建一个log4j.properties文件….

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layo
1429e
ut.ConversionPattern=%5p [%t] - %m%n


创建mybatis 核心文件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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="itcast"/>
</dataSource>
</environment>
</environments>
</configuration>


创建sql映射文件,因为mybatis是半自动化sql的框架,所以sql这边还是我们自己写的……所以我们需要创建sql映射文件

在config目录下创建一个sqlmap文件夹,里面创建一个pojo的映射文件….

<?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语句,后面会讲另一层非常重要的作用。-->
<mapper namespace="test">

<!--parameterType:定义输入到sql中的映射类型,#{id}表示使用preparedstatement设置占位符号并将输入变量id传到sql,其实就相当于jdbc中的 ? -->
<!--resultType:定义输出结果映射类型。-->
<select id="findUserById" parameterType="int" resultType="cn.mybatis.pojo.User">
select * from user where id = #{id}
</select>
</mapper>


这里说明一下. 类型如果是八种基本类型的一种,可以直接写,如果不是,需要写类的全路径 比如 java.lang.String,当然,mybatis也提供了一些别名,写别名也是可以的,我个人比较喜欢全路径名,,别名还要记,麻烦,下面是mybatis支持的别名,有兴趣的小伙伴可以看看



这里提一下,mybatis支持自定义别名,后面我会讲,

创建完映射文件后,我们需要在核心配置文件里引入一下映射文件,

<mappers>
<mapper resource="sqlmap/User.xml"></mapper>
</mappers>


环境已经搭建的差不多了,我们来看看目录结构



现在我们就来使用刚刚写的一条sql语句,做一个查询小案例

package test;

import cn.mybatis.pojo.User;
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 org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

public class Demo {

@Test
public void fun01() throws IOException {
String resources = "mybatisConfig.xml";

//Resources.getResourceAsStream(resources)  这句代码的意思就是查找classpath目录下的mybatisConfig.xml文件
InputStream stream = Resources.getResourceAsStream(resources);
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//获取工厂
SqlSessionFactory factory = builder.build(stream);
//获取session
SqlSession session = factory.openSession();

//test.findUserById      映射文件中的名称空间.查询语句的id    目的是确定使用具体的哪一条sql
User user = session.selectOne("test.findUserById", 1);

System.out.println(user);

session.close();
}
}


运行代码如下



嗯,然后我们趁热打铁,写一个插入sql的小案例,

因为我们需要写sql,所以我们需要去映射文件里面添加一条sql语句 ,需要注意的是 #{}里面的值需要跟pojo里面的属性名一致,属性名可以理解为成员变量名

<insert id="insert" parameterType="cn.mybatis.pojo.User">
insert into user(username,birthday,sex,address) VALUE(#{username},#{birthday},#{sex},#{address});
</insert>


然后写测试代码

@Test
public void insert() throws IOException {
String resources = "mybatisConfig.xml";

//Resources.getResourceAsStream(resources)  这句代码的意思就是查找classpath目录下的mybatisConfig.xml文件
InputStream stream = Resources.getResourceAsStream(resources);
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//获取工厂
SqlSessionFactory factory = builder.build(stream);
//获取session
SqlSession session = factory.openSession();

//test.findUserById      映射文件中的名称空间.查询语句的id    目的是确定使用具体的哪一条sql
User user = new User();

user.setUsername("李白");
user.setSex("男");
user.setAddress("广东省");
user.setBirthday(new Date());
session.insert("test.insert", user);

session.close();
}


我们来看执行结果



回滚的原因是没有提交事务,我们需要手动提交事务,增删改都需要提交事务,这是需要注意的.

我们添加 session.commit();再进行测试



这里有个小案例,需求是:执行插入语句的同时获取插入时的id,

这里我一开始想的办法是先插入,再查询最大的id,返回,但是这种方案在访问量大的时候就会失效,这是不安全的,由此我们需要使用数据库提供的函数来解决这个问题, LAST_INSERT_ID()

我们来修改映射文件中的sql语句,

<insert id="insert_getId" parameterType="cn.mybatis.pojo.User">
<selectKey keyProperty="id" resultType="int" order="AFTER">
select LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address) VALUE(#{username},#{birthday},#{sex},#{address});
</insert>


keyProperty : 返回的主键存储在pojo中的哪个属性

resultType : 返回数据类型

order:selectKey的执行顺序,是相对与insert语句来说,由于mysql的自增原理执行完insert语句之后才将主键生成,所以这里selectKey的执行顺序为after

测试代码

@Test
public void insert() throws IOException {
String resources = "mybatisConfig.xml";

//Resources.getResourceAsStream(resources)  这句代码的意思就是查找classpath目录下的mybatisConfig.xml文件
InputStream stream = Resources.getResourceAsStream(resources);
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//获取工厂
SqlSessionFactory factory = builder.build(stream);
//获取session
SqlSession session = factory.openSession();

//test.findUserById      映射文件中的名称空间.查询语句的id    目的是确定使用具体的哪一条sql
User user = new User();

user.setUsername("李白");
user.setSex("男");
user.setAddress("广东省");
user.setBirthday(new Date());

System.out.println("执行sql前的user对象user="+user);

session.insert("test.insert_getId", user);

System.out.println("执行sql后的user对象user="+user);
session.commit();
session.close();
}


执行结果如下



我们可以发现,执行完sql后对象的id给赋值了

如果主键id 是uuid生成的,那么又要重写一条sql

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<selectKey resultType="java.lang.String" order="BEFORE"
keyProperty="id">
select uuid()
</selectKey>
insert into user(id,username,birthday,sex,address)
values(#{id},#{username},#{birthday},#{sex},#{address})
</insert>


这里使用uuid 的原因是, 执行sql前,id都没生成,所以我们需要提前生成id,

删改我就不演示了,重复造轮子,感觉没必要了.

嗯,我们来抽取一下代码,

SqlSessionFactory factory;
InputStream stream;
@Before
public void createSqlSessionFactory(){
String resources = "mybatisConfig.xml";

//Resources.getResourceAsStream(resources)  这句代码的意思就是查找classpath目录下的mybatisConfig.xml文件
try {
stream = Resources.getResourceAsStream(resources);
}catch (Exception e){

}

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//获取工厂
factory = builder.build(stream);
}


看完这段代码估计就有小朋友有疑问了,@Before 是干啥的?? 其实在方法上增加@Before主键后,哪个方法就会在执行@Test注解方法前执行一遍,嗯,是的没错..相信我,

抽取完这段代码后,我们就可以不用再获取factory了,直接用成员变量就可以了…..

现在又有一个需求,其实就是模糊查询…给一个用户名,模糊查询所有,,,,,

我们先在映射文件里写一条sql语句

<select id="mohuchaxun" resultType="cn.mybatis.pojo.User"       parameterType="java.lang.String">
select * from user where username like '%${value}%'
</select>


这里需要注意的是 这里不能使用 #{} 了,因为#{} 只是单词的占位符,并不能字符串拼接,, 还需要注意的是 ${}的值只能使用value,

然后写测试代码

@Test
public void likeFind() throws IOException {
//获取session
SqlSession session = factory.openSession();

List<User> users = session.selectList("test.mohuchaxun", "小");

System.out.println("user="+users);
session.close();
}


测试运行结果如下



学到这里,我们的myBatis就已经是入门了,,,,,,,,

然后这里做个小结

#{}和${}

#{}其实是占位符的意思,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换.#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
${}的意思的拼接符的意思,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。
如果:
输入参数的数据类型是简单的数据类型,
#{} 里面的名称随意写
而${} 里面的参数名称必须是value.


parameterType和resultType

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

resultType指定输出参数类型,mybatis 通过sql记录数据映射为resultType指定类型的对象,
如果返回的是集合,只需要指定集合里面的元素的数据类型即可,


selectOne和selectList

其实selectOne的底层就是使用selectList实现的,只不过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可以查询一条或多条记录。


我们来看看selectOne底层实现原理…….



顺便说一下好了,selectList的底层使用jdbc来做的,有兴趣的小伙伴可以翻翻,

嗯,看到这里应该有些小伙伴已经不耐烦了,那个,,,别打我,因为现在重点才开始

mybatis Mapper动态代理方式

学习代理方式之前,我们需要了解一些规则,因为我们需要根据这种规则才能使用功能,

Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。

遵循规范如下:

namespace 需要与接口的类路径相同,

Mapper接口方法名和Mapper.xml中定义的每个statement的id相同

Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同

Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

Mapper.xml(映射文件)

定义mapper映射文件UserMapper.xml(内容同User.xml),需要修改namespace的值为 UserMapper接口路径。将UserMapper.xml放在classpath 下mapper目录 下。

接口定义

Mapper接口方法名和Mapper.xml中定义的statement的id相同

Mapper接口方法的输入参数类型和mapper.xml中定义的statement的parameterType的类型相同

-Mapper接口方法的输出参数类型和mapper.xml中定义的statement的resultType的类型相同

创建一个UserMapper文件,拷贝之前的User.xml就行,放在config目录下的mapper目录下,

还需要在核心配置文件里引入一下mapper文件,,

<mappers>
<!--<mapper resource="sqlmap/User.xml"></mapper>-->
<mapper resource="mapper/UserMapper.xml"></mapper>
</mappers>


然后创建一个dao接口,遵守以上规则,,,

package cn.mybatis.dao;

import cn.mybatis.pojo.User;

import java.util.List;

public interface IUserDao {
//这里就写一个模糊查询的例子了
public List<User> mohuchaxun(String name);
}


写到这里,还需要改userMapper文件,因为规范要求namespace 跟 mapper接口的类路径一致,

<mapper namespace="cn.mybatis.dao.IUserDao">
xxxxxx
</mapper>


测试代码如下

@Test
public void test_fun02(){
//获取session
SqlSession session = factory.openSession();
IUserDao mapper = session.getMapper(IUserDao.class);

List<User> user = mapper.mohuchaxun("小");

System.out.println("user="+user);
}


运行结果



代码就讲到这里,其实也没什么难度,,只要遵守规则写就好了,,,,



代码就讲的差不多了,接下来就讲讲SqlMapConfig.xml核心配置文件把,,,

配置内容如下

SqlMapConfig.xml中配置的内容和顺序如下:必须按照顺序配置

properties(属性)

settings(全局配置参数)

typeAliases(类型别名)

typeHandlers(类型处理器)

objectFactory(对象工厂)

plugins(插件)

environments(环境集合属性对象)

environment(环境子属性对象)

transactionManager(事务管理)

dataSource(数据源)

mappers(映射器)

那个,别担心,我们不是所有都需要会,,只需要会几个重点配置就行了……说实话,我第一次看到有这么多配置的时候都吓了一跳,,,,

需要了解的配置如下

properties(属性)

typeAliases(类型别名)

mappers(映射器)

需要注意的是 必须按照顺序配置 必须按照顺序配置 必须按照顺序配置,

首先我们来试试properties

在resource目录下创建xxx.properties文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=1039191520


然后在核心配置文件里引用一下

<properties resource="datasource.properties"></properties>

<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<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>


运行测试



typeAliases(类型别名)

之前我们就讲了myBatis支持的一些类型别名,, 这里我就大致的讲一些怎么自定义类型别名把……

配置核心配置文件,记住配置顺序,不能放在properties 配置前面,

<properties resource="datasource.properties"></properties>

<typeAliases>
<!--<typeAlias alias="user" type="cn.mybatis.pojo.User"/>   <!–单个别名定义–>-->

<package name="cn.mybatis.pojo" />   <!--多个别名定义,扫描整个包下的类,别名为类名(大小写不敏感)-->
</typeAliases>


然后我们修改代码,使用别名,就改模糊查询的例子了,因为突出大小写不敏感,所以嘿嘿嘿,你懂的

<select id="mohuchaxun" resultType="uSeR" parameterType="java.lang.String">
select * from user where username like '%${value}%'
</select>


代码测试



最后来讲讲mappers(映射器)

相信大家已经有所感悟了把,我们写mapper一直都是一个个的引入的,这样要是在开发中可是很头疼的一件事,mybatis提供了解决方案

此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

<mappers>
<!--<mapper resource="sqlmap/User.xml"></mapper>-->
<!--<mapper resource="mapper/UserMapper.xml"></mapper>-->
<package name="cn.mybatis.dao"></package>
</mappers>


我们需要重新修改一下目录结构



然后运行测试



myBatis入门就讲到这里,下次讲myBatis拼接sql等等…..撤退啦
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  apache java mybatis 框架 ssm