您的位置:首页 > 其它

mybatis简单入门

2016-10-10 14:52 411 查看
之前我们学习了hibernate,今天我们来学习下mybatis。网上对于这两个orm框架的争论可以说很激烈,这里我们不做瑜亮之争,只是单纯的学习mybatis。

mybatis的有点:1.学习简单;2.mybatis需要手写sql(半自动化),所以调优会很简单。3.作为一个orm框架,使用方便是肯定的了。

下面我们来进行简单的学习使用mybatis。

一:初识mybatis

首先我们创建一个maven工程test_mybatis。

pom.xml

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>

<!-- mysql连接 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>

<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

</dependencies>
package com.julyday.test_mybatis.entity;

public class User {
private int id;
private String name;
private int age;

public User() {

}

public User(String name, int age) {
this.name = name;
this.age = age;
}

//getter setter

@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
}

}

mybatis的mapper文件

<?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">
<resultMap type="com.julyday.test_mybatis.entity.User" id="UserResult">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="age" jdbcType="INTEGER" property="age" />
</resultMap>

<sql id="col">
id,name,age
</sql>

<insert id="insert" useGeneratedKeys="true" >
insert into user(name,age) values (#{name,jdbcType=VARCHAR},#{age,jdbcType=INTEGER})
</insert>

<select id="find" resultMap="UserResult">
SELECT <include refid="col"/> FROM user WHERE id = #{id,jdbcType=INTEGER}
</select>

<select id="selectOrder" resultMap="UserResult">
SELECT <include refid="col"/> FROM user order by ${_parameter}
</select>

<select id="getList" parameterType="com.julyday.test_mybatis.entity.User" resultMap="UserResult">
SELECT <include refid="col"/> FROM user
<where>
<if test="name != null and !"".equals(name.trim())">
name = #{name,jdbcType=VARCHAR}
</if>
<if test="age > 0">
and age = #{age,jdbcType=INTEGER}
</if>
</where>
</select>

<select id="sqlInject" parameterType="User" resultMap="UserResult">
SELECT <include refid="col"/> FROM user
<where>
<if test="name != null and !"".equals(name.trim())">
name = ${name}
</if>
<if test="age > 0">
and age = #{age,jdbcType=INTEGER}
</if>
</where>
</select>

<update id="update">
update user
<set>
<if test="name != null and !"".equals(name.trim())">
name = #{name,jdbcType=VARCHAR},
</if>
<if test="age > 0">
age = #{age,jdbcType=INTEGER}
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>

<delete id="delete">
delete from user where id = #{id,jdbcType=INTEGER}
</delete>

</mapper>


resultMap:返回结果,type对应我们的实体,id别名。

id:表示主键

column:数据库对应字段

jdbcType:表示对应的jdbc类型,写jdbc的同学可能比较熟悉(java.sql.Types),对象的数据库类型有个对应关系,这里不多说了。

property:实体中的属性字段

sql:不是我们通常意义上的sql,他是为了简便字段使用的,当字段个数较多是很有用,同时也不会有n+1的情况出现。
insert,select,update,delete:对应的数据库操作。select中<include refid="col"/>,就是用到我们之前的sql了。

where:对应了数据库中的关键字,在这里,如果里面没有查询条件就不含where关键字,同样如果第一个含有and或者or他会去除,我们这如果name没值,age前的and会去除。

set:同where。

${}和#{}的区别:select * from user where name = ${name},当参数为字符串类型时,${name}是“julyday”,结果是select * from user where name = julyday,而#{name}的结果是select
* from user where name = 'julyday',这个就像我们在jdbc中直接字符串+ 和 setString()的对比一样,前者会出现sql注入的风险,name的传值是“'' or 1=1”,这样前一个就查了全表,后一个查询结果是0条。当然在order by的后面我们是需要用#{},不然排序是不起作用的。

这里为方便我们排查错误我们可以查看日志,但是mybatis没有像hibernate一样提供自己的日志服务,我们需要第三方的log4j来打印日志。

log4j.rootLogger=debug,stdout,logfile
### 把日志信息输出到控制台 ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
### 把日志信息输出到文件:jbit.log ###
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=D:/test.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=[test_mybatis][%p] %d{yyyy-MM-dd HH:mm:ss} %F %m%n

###显示SQL语句部分
log4j.logger.com.ibatis=DEBUG
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUGlog4j的配置这里就不再赘述了。
当然mapper这个文件可以在源码的找到,不会写的朋友可以自己下载源码看下,~\src\test\java\org\apache\ibatis\submitted\complex_property下,包括下面的Configuration.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>
<!--
<settings>
<setting name="useGeneratedKeys" value="false"/>
<setting name="useColumnLabel" value="true"/>
</settings>
-->
<typeAliases>
<typeAlias alias="User" type="com.julyday.test_mybatis.entity.User"/>
</typeAliases>

<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="" value=""/>
</transactionManager>
<dataSource type="UNPOOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>

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

</configuration>typeAliases:给我们的实体启一个别名

environments:数据库的配置信息

mappers:对应的mapper文件

下面是我们的测试文件:

package com.julyday.test_mybatis;

import java.io.IOException;
import java.io.Reader;
import java.util.List;

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.After;
import org.junit.Before;
import org.junit.Test;

import com.julyday.test_mybatis.entity.User;

public class TestMybatis {
private SqlSession sqlSession;

@Before
public void init() {
Reader reader;
try {
reader = Resources.getResourceAsReader("Configuration.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(reader);
sqlSession = sqlSessionFactory.openSession();
} catch (IOException e) {
e.printStackTrace();
}
}

@Test
public void testInsert() {
User u = new User("julyday", 18);
sqlSession.insert("User.insert", u);
sqlSession.commit();
}

@Test
public void testFind() {
User u = sqlSession.selectOne("User.find", 1);
System.out.println(u);
}

@Test
public void testGetList() {
User user = new User();
//user.setAge(18);
//user.setName("julyday");
user.setName("'' or 1=1 ");
//List<User> list = sqlSession.selectList("User.getList", user);
List<User> list = sqlSession.selectList("User.sqlInject", user);
System.out.println(list.size());
for(User u : list){
System.out.println(u);
}
}

@Test
public void testSelectOrder() {
List<User> list = sqlSession.selectList("User.selectOrder", "age desc");
System.out.println(list.size());
for(User u : list){
System.out.println(u);
}
}

@Test
public void testUpdate() {
User u = sqlSession.selectOne("User.find", 1);
u.setAge(12);
sqlSession.update("User.update", u);
sqlSession.commit();
}

@Test
public void testDelete() {
sqlSession.delete("User.delete",1);
}

@After
public void destory() {
sqlSession.close();
}
}

二:面向接口编程

package com.julyday.test_mybatis.dao;

import java.util.List;

import com.julyday.test_mybatis.entity.User;

public interface UserDao {
public void insert(User user);

public User find(int id);

public List<User> selectOrder(String order);

public List<User> getList(User user);

public List<User> sqlInject(User user);

public void update(User user);

public void delete(int id);
}
copy一下User.xml成UserDao.xml
修改<mapper namespace="com.julyday.test_mybatis.dao.UserDao">,这个命名空间必须唯一,这是反射的基础。这里就简单的看下源码就知道了,同时也会加深你对mybatis的理解。可以从ud = sqlSession.getMapper(UserDao.class);这个开始,在DefaultSqlSession类里面,当然你必须对代理和反射有一定的了解,这里简单的说下可以看MapperProxy.cachedMapperMethod()方法。
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
反射的invoke方法最后一句return mapperMethod.execute(sqlSession, args);就是正文了,MapperMethod这个类就是他的庐山真面目了,后面根据我们的sql类型找到对应的分支看下。这个就不继续下去了。
我们的测试类:
package com.julyday.test_mybatis;

import java.io.IOException;
import java.io.Reader;
import java.util.List;

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.After;
import org.junit.Before;
import org.junit.Test;

import com.julyday.test_mybatis.dao.UserDao;
import com.julyday.test_mybatis.entity.User;

public class TestDao {
private SqlSession sqlSession;
private UserDao ud ;
@Before
public void init() {
Reader reader;
try {
reader = Resources.getResourceAsReader("Configuration.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(reader);
sqlSession = sqlSessionFactory.openSession();
ud = sqlSession.getMapper(UserDao.class);
} catch (IOException e) {
e.printStackTrace();
}
}

@Test
public void testInsert() {
User u = new User("zhangsan", 28);
ud.insert(u);
sqlSession.commit();
}

@Test
public void testFind() {
User u = ud.find(1);
System.out.println(u);
}

@Test
public void testGetList() {
User user = new User();
//user.setAge(18);
//user.setName("julyday");
user.setName("'' or 1=1 ");
//List<User> list =ud.getList(user);
List<User> list = ud.sqlInject(user);
System.out.println(list.size());
for(User u : list){
System.out.println(u);
}
}

@Test
public void testSelectOrder() {
List<User> list = ud.selectOrder("age desc");
System.out.println(list.size());
for(User u : list){
System.out.println(u);
}
}

@Test
public void testUpdate() {
User u = ud.find(1);
u.setAge(19);
ud.update(u);
sqlSession.commit();
}

@Test
public void testDelete() {
ud.delete(3);
sqlSession.commit();
}

@After
public void destory() {
sqlSession.close();
}
}

三:mybatis自动化工具类generator

首先是jar包的下载:mybatis-generator-core-1.3.2.jar。jar下载
这里我放在D:\generator,写一个generator.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- 数据库驱动包位置 -->
<classPathEntry location="D:\generator\mysql-connector-java-5.1.34.jar" />
<!-- <classPathEntry location="C:\oracle\product\10.2.0\db_1\jdbc\lib\ojdbc14.jar" />-->
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<commentGenerator>
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!-- 数据库链接URL、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root" password="root">
<!--<jdbcConnection driverClass="oracle.jdbc.driver.OracleDriver" connectionURL="jdbc:oracle:thin:@localhost:1521:orcl" userId="msa" password="msa">-->
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- 生成模型的包名和位置 -->
<javaModelGenerator targetPackage="com.julyday.test_mybatis.entity" targetProject="D:\generator\src">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- 生成的映射文件包名和位置 -->
<sqlMapGenerator targetPackage="mybatis" targetProject="D:\generator\src">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- 生成DAO的包名和位置 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.julyday.test_mybatis.dao" targetProject="D:\generator\src">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- 要生成那些表(更改tableName和domainObjectName就可以) -->
<table tableName="user" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false" />
</context>
</generatorConfiguration>
然后就是执行了,java -jar mybatis-generator-core-1.3.2.jar -configfile
generator.xml -overwrite  这里targetProject目录是必须要存在的,可以写成你eclipse项目的路径。
这里我们就简单的说下最后一个table,很明显是数据库的表到类的映射,第一个是表名,第二个是类名,后面的根据英文大家都能猜到是干啥的,不明白的大家可以自己尝试下。多个表的话就写对个table。

四:表关联关系

一对多:
实体类不看了,有需要的朋友下代码看。
mapper文件:
<?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="Student">
<resultMap type="com.julyday.test_mybatis.entity.Student" id="StudentResult">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="age" jdbcType="INTEGER" property="age" />
<result column="gid" jdbcType="INTEGER" property="gid" />
</resultMap>

<select id="find" resultMap="StudentResult">
SELECT id,name,age,gid FROM student WHERE id = #{id,jdbcType=INTEGER}
</select>

</mapper>
<?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="Grade">
<resultMap type="com.julyday.test_mybatis.entity.Grade" id="GradeResult">
<id column="g_id" jdbcType="INTEGER" property="id" />
<result column="gname" jdbcType="VARCHAR" property="gname" />
<result column="gdesc" jdbcType="VARCHAR" property="gdesc" />
<collection property="students" resultMap="Student.StudentResult" />
<!-- <collection property="students" ofType="com.julyday.test_mybatis.entity.Student" column="gid">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="age" jdbcType="INTEGER" property="age" />
<result column="gid" jdbcType="INTEGER" property="gid" />
</collection>-->
</resultMap>

<select id="find" resultMap="GradeResult">
SELECT id as g_id,gname,gdesc FROM grade WHERE id = #{id,jdbcType=INTEGER}
</select>

<select id="findAll" parameterType="com.julyday.test_mybatis.entity.Grade" resultMap="GradeResult">
SELECT g.id as g_id,g.gname,g.gdesc,s.id,s.name,s.age,s.gid
FROM Grade g left join student s on g.id = s.gid
where g.id=#{id,jdbcType=INTEGER}
</select>
</mapper>
一对多,一的一方用collection,两种collection任选一个。
@Test
public void testFindall() {
Grade grade = new Grade();
grade.setId(1);
List<Grade> list = sqlSession.selectList("Grade.findAll",grade);
for(Grade g : list){
System.out.println(g.toString());
List<Student> ls = g.getStudents();
for(Student s : ls){
System.out.println(s.toString());
}
}
}
测试没问题。

多对一:
<?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="Order">
<resultMap type="com.julyday.test_mybatis.entity.Order" id="OrderResult">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
</resultMap>

<select id="find" resultMap="OrderResult">
SELECT id,name FROM orders WHERE id = #{id,jdbcType=INTEGER}
</select>
</mapper>

<?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="Product">
<resultMap type="com.julyday.test_mybatis.entity.Product" id="ProductResult">
<id column="p_id" jdbcType="INTEGER" property="id"/>
<result column="p_name" jdbcType="VARCHAR" property="name"/>
<result column="price" jdbcType="INTEGER" property="price"/>
<result column="oid" jdbcType="INTEGER" property="oid"/>

<association property="order" javaType="com.julyday.test_mybatis.entity.Order">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
</association>
<!-- <association property="order" resultMap="Order.OrderResult"/>-->
</resultMap>

<select id="find" resultMap="ProductResult">
SELECT id as p_id,name as p_name,price,oid FROM product WHERE id = #{id,jdbcType=INTEGER}
</select>

<select id="findAll" resultMap="ProductResult">
SELECT p.id as p_id,p.name as p_name,p.price,p.oid,o.id,o.name FROM
product p right join orders o on p.oid = o.id WHERE p.id = #{id,jdbcType=INTEGER}
</select>

</mapper>
多对一,用association,同样的两个association选一个。
@Test
public void testFindall() {
Product product = new Product();
product.setId(3);
List<Product> list = sqlSession.selectList("Product.findAll",product);
for(Product p : list){
System.out.println(p.toString());
Order o  = p.getOrder();
System.out.println(o.toString());
}
}
测试OK.

最后国际惯例,贴上全部代码的git地址:代码下载地址
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: