前言
MyBatis是一个优秀的持久层框架。原生的jdbc操作存在大量的重复性代码(如注册驱动,创建连接,创建statement,结果集检测等)。框架的作用就是把这些繁琐的代码封装。
MyBatis通过XML或者注解的方式将要执行的sql语句配置起来,并通过java对象和sql语句映射成最终执行的sql语句。最终由MyBatis框架执行sql,并将结果映射成java对象并返回。
正文
准备jar包
- mybatis-3.4.6.jar
- mysql-connector-java-5.1.47.jar
mysql数据库为firstdb,表名为xtb,表结构如下
1.新建java project MybatisPro ,项目结构图:
一共五个文件
在src下新建com.domain包,在新建User.java
-
package com.domain; -
public class User { -
private Integer user_id; -
private String user_name; -
private String user_sex; -
private String user_phone; -
public String toString() { -
return "User [user_id=" + user_id + ", user_name=" + user_name + ", user_sex=" + user_sex + ", user_phone=" -
+ user_phone + "]"; -
} -
public String getUser_phone() { -
return user_phone; -
} -
public void setUser_phone(String user_phone) { -
this.user_phone = user_phone; -
} -
public String getUser_sex() { -
return user_sex; -
} -
public void setUser_sex(String user_sex) { -
this.user_sex = user_sex; -
} -
public String getUser_name() { -
return user_name; -
} -
public void setUser_name(String user_name) { -
this.user_name = user_name; -
} -
public Integer getUser_id() { -
return user_id; -
} -
public void setUser_id(Integer user_id) { -
this.user_id = user_id; -
} -
}
在src下新建com.Dao包,然后新建Interface文件,UserMapper.java
-
package com.Dao; -
import com.domain.*; -
public interface UserMapper { -
public User findUserById(int id) throws Exception; -
public void insertUser(User user) throws Exception; -
}
在src下新建全局配置文件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/firstdb"/><!--用自己的数据库名字 --> -
<property name="username" value="root"/> <!-- 用自己的用户名密码 --> -
<property name="password" value=""/> -
</dataSource> -
</environment> -
</environments> -
<mappers> -
<mapper resource="UserMapper.xml"/> <!-- 这里配置映射文件 --> -
</mappers> -
</configuration>
新建映射配置文件UserMpper.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属性,不然会报错,可看做包名--> -
<mapper namespace="com.Dao.UserMapper"> -
<select id="findUserById" parameterType="int" resultType="com.domain.User"> -
select * from xtb where user_id = #{id} -
</select> -
<insert id="insertUser" parameterType="com.domain.User"> -
insert into xtb(user_name,user_sex,user_phone) values(#{user_name},#{user_sex},#{user_phone}) -
</insert> -
</mapper>
最后,新建测试类Test.java
-
package com.test; -
import java.io.InputStream; -
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 com.Dao.UserMapper; -
import com.domain.User; -
public class Test{ -
public static void main(String[] args) throws Exception { -
testInsertUser(); -
SelectByid(); -
} -
public static void SelectByid() throws Exception{ -
String resource = "SqlMapConfig.xml"; -
InputStream inputStream = Resources.getResourceAsStream(resource); -
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); -
SqlSession session = factory.openSession(); -
//--------------- -
UserMapper userMapper = session.getMapper(UserMapper.class); -
User user = userMapper.findUserById(2); -
System.out.println(user); -
//-------------- -
session.close(); -
} -
public static void testInsertUser() throws Exception{ -
String resource = "SqlMapConfig.xml"; -
InputStream inputStream = Resources.getResourceAsStream(resource); -
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); -
SqlSession session = factory.openSession(); -
//--------------------- -
User user = new User(); -
user.setUser_name("lalala"); -
user.setUser_sex("women"); -
user.setUser_phone("0123345"); -
UserMapper mapper = session.getMapper(UserMapper.class); -
mapper.insertUser(user); -
session.commit(); -
//---------------------- -
session.close(); -
} -
}
运行程序,查看结果:
常见错误解决:
基本上都是UserMapper.xml和接口UserMap.java的对应关系没有配置好,我把UserMapper.xml和UserMap.java拼在一起可以看下自己的配置是否正确:
简单来说就是:接口的包名,类名,参数,返回值分别对应着映射文件的namespace,id,parameterType,resultType。
总结原理:
mybais运用了代理技术,实例化出接口UserMapper的实例,然后通过根据配置文件调用sql.
具体流程:
1.读取配置文件SqlMapConfig.xml 获取连数据库的相关信息
2.有了这些信息就能创建SqlSessionFactory
3.SqlSessionFactory建立SqlSession
4.SqlSession 通过代理创建出UserMapper接口的实例,并从userMapper.xml中读取信息
5.通过userMapper.xml中的信息,执行sql语句
6.返回结果,关闭session
********************************以下为Mybatis使用过程中的注意事项*********************************************
原文连接:https://www.cnblogs.com/pretty-boy/p/5306549.html
使用Mybatis时请注意这两个参数,否则会让你的数据库连接爆掉
目前正在开发一个产品的服务器端代码,持久层我选择了Mybatis3(也就是原来的ibatis)作为框架,之所以选择他理由就是我觉得Hibernate搞起来貌似很复杂,我不太会用,哈哈(上家公司留下的阴影,用Hibernate搞得我想死)。上周完成了大部分代码的开发工作,想着既然是要发布的产品,于是找来Jmeter做压力测试,结果这一测,暴露问题了,mysql返回"too many connections"这个error,这个error的具体解释参照这个链接http://dev.mysql.com/doc//refman/5.5/en/too-many-connections.html。
一般持久层与数据库连接都会通过一个连接池(pooled datasource)管理,方便复用连接,控制并发,比较有名的有DBCP,C3P0,BONECP等等。Mybatis3自己实现了一个连接池,在配置文件中指定datasource的type属性为POOLED即可使用。与并发关系较大的两个Mybatis连接池参数是poolMaximumActiveConnections和poolMaximumIdleConnections。
好了,出了问题,自然得找文档(官方手册,中英文皆有),poolMaximumActiveConnections是最大的活动连接数,活动连接,顾名思义,就是正在与数据库交互的连接,默认是10,poolMaximumIdleConnections是空闲连接数,就是没有处理请求的连接,默认是5。Mysql的max_connections我设置的是200,既最大连接数。这样一看,好像找不到问题所在,连接池最大的活动连接也就是10,跟200比还差很远,Mysql怎么会返回"too many connections"呢?在查阅文档无果后,我请教周围的一位同事,他虽然没用过Mybatis,但是他说是不是请求数超过poolMaximumActiveConnections后mybatis还会去获取连接,是不是有这样的参数控制,然后让我看看源码,说开源的东西嘛,搞不清楚就看源码。
我一向对源码抱有恐惧的心理,感觉那都是大神写的,我等屌丝怎能看得懂,不过被逼无奈,翻出Mybatis的源码看了一看,结果豁然开朗。找到org.apache.ibatis.datasource.pooled包下面的PooledDataSource类,这个就是连接池的实现类。可以看到里面定义了几个参数,其中就包括poolMaximumActiveConnections和poolMaximumIdleConnections,找到pushConnection方法,这个方法里会判断当前空闲连接数和poolMaximumIdleConnections的大小,如果小于他,会new PooledConnection并放进队列中,这就导致一个问题,当所有的连接被占满后,Mybatis为了保持一定的空闲连接,会不断获取新的连接,然后这些新连接被占用后,就会再去new PooledConnection,结果就是超过了mysql设置的最大连接数,然后数据库返回该错误。不知道这算不算是Mybatis的一个"坑"吧,总之在使用时要小心了,并发量大的时候就会爆掉你的数据库,解决办法很简单,将poolMaximumIdleConnections设置为0即可,果然改掉后压力测试不会爆掉数据库。
现在回想起来,官方文档对poolMaximumIdleConnections的定义是:在任意时间存在的空闲连接数,完全就解释了这个参数的含义,只不过当时没有仔细想,那这个参数是不是该改名字叫poolPermanentIdleConnections比较好呢,呵呵。
问题解决了,很开心,晚上回去再仔细读下里面的源码,看看还有没有别的没发现的问题。看来源码也不是想象中的那么神秘和高深啊。其实为什么那个同事一下就能看出问题的大概,一方面是经验丰富,另一方面可能与他理解数据库连接池机制有关,归根到底,基础的东西还是最重要的。
回去认真读了Mybatis源码,发现自己错了,特此更正,以免误导读者,实在是对不起。其实poolMaximumActiveConnections的存在可以正确地限制数据库连接池并发访问数据的连接数,没有问题,之所以我的数据库爆掉了,是我没有正确地维持SqlSessionFactory这个类的一个单例。在使用时一定要保持一个全局唯一的SqlSessionFactory