druid官方文檔:https://github.com/alibaba/druid/wiki/常見問題css
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.19</version> </dependency>
<!--mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.1</version> </dependency> <!--通用mapper--> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> <version>1.1.5</version> </dependency> <!--pagehelper 分頁插件--> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.3</version> </dependency> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <!-- 要打包了這個生成代碼要禁止掉,本地開發開啓--> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.5</version> <dependencies> <!-- 配置這個依賴主要是爲了等下在配置mybatis-generator.xml的時候能夠不用配置 classPathEntry 這樣的一個屬性, 避免代碼的耦合度過高--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.44</version> </dependency> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper</artifactId> <version>3.4.0</version> </dependency> </dependencies> <executions> <execution> <id>Generate MyBatis Artifacts</id> <phase>package</phase> <goals> <goal>generate</goal> </goals> </execution> </executions> <configuration> <!--容許移動生成的文件 --> <verbose>true</verbose> <!-- 是否覆蓋 --> <overwrite>true</overwrite> <!-- 自動生成的配置 --> <configurationFile>src/main/resources/mybatis-generator.xml</configurationFile> </configuration> </plugin> </plugins> </build>
## 數據庫訪問配置 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.driver-class-name = com.mysql.jdbc.Driver spring.datasource.url = jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=utf-8 spring.datasource.username = root spring.datasource.password = root # 下面爲鏈接池的補充設置,應用到上面全部數據源中 # 初始化大小,最小,最大 spring.datasource.initialSize=5 spring.datasource.minIdle=5 spring.datasource.maxActive=20 # 配置獲取鏈接等待超時的時間 spring.datasource.maxWait=60000 # 配置間隔多久才進行一次檢測,檢測須要關閉的空閒鏈接,單位是毫秒 spring.datasource.timeBetweenEvictionRunsMillis=60000 # 配置一個鏈接在池中最小生存的時間,單位是毫秒 spring.datasource.minEvictableIdleTimeMillis=300000 spring.datasource.validationQuery=SELECT 1 FROM DUAL spring.datasource.testWhileIdle=true spring.datasource.testOnBorrow=false spring.datasource.testOnReturn=false # 打開PSCache,而且指定每一個鏈接上PSCache的大小 spring.datasource.poolPreparedStatements=true spring.datasource.maxPoolPreparedStatementPerConnectionSize=20 # 配置監控統計攔截的filters,去掉後監控界面sql沒法統計,'wall'用於防火牆 spring.datasource.filters=stat,wall,log4j # 經過connectProperties屬性來打開mergeSql功能;慢SQL記錄 #spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 # 合併多個DruidDataSource的監控數據 #spring.datasource.useGlobalDataSourceStat=true #指定 domain bean所在包 mybatis.type-aliases-package=com.dudu.domain #指定 mapper 映射文件 mybatis.mapperLocations=classpath:mapper/*.xml #mapper #mappers 多個接口時逗號隔開 mapper.mappers=com.dudu.util.MyMapper mapper.not-empty=false mapper.identity=MYSQL #pagehelper pagehelper.helperDialect=mysql pagehelper.reasonable=true pagehelper.supportMethodsArguments=true pagehelper.params=count=countSql
@Configuration public class DruidConfig { private Logger logger = LoggerFactory.getLogger(DruidConfig.class); @Value("${spring.datasource.url:#{null}}") private String dbUrl; @Value("${spring.datasource.username: #{null}}") private String username; @Value("${spring.datasource.password:#{null}}") private String password; @Value("${spring.datasource.driverClassName:#{null}}") private String driverClassName; @Value("${spring.datasource.initialSize:#{null}}") private Integer initialSize; @Value("${spring.datasource.minIdle:#{null}}") private Integer minIdle; @Value("${spring.datasource.maxActive:#{null}}") private Integer maxActive; @Value("${spring.datasource.maxWait:#{null}}") private Integer maxWait; @Value("${spring.datasource.timeBetweenEvictionRunsMillis:#{null}}") private Integer timeBetweenEvictionRunsMillis; @Value("${spring.datasource.minEvictableIdleTimeMillis:#{null}}") private Integer minEvictableIdleTimeMillis; @Value("${spring.datasource.validationQuery:#{null}}") private String validationQuery; @Value("${spring.datasource.testWhileIdle:#{null}}") private Boolean testWhileIdle; @Value("${spring.datasource.testOnBorrow:#{null}}") private Boolean testOnBorrow; @Value("${spring.datasource.testOnReturn:#{null}}") private Boolean testOnReturn; @Value("${spring.datasource.poolPreparedStatements:#{null}}") private Boolean poolPreparedStatements; @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize:#{null}}") private Integer maxPoolPreparedStatementPerConnectionSize; @Value("${spring.datasource.filters:#{null}}") private String filters; @Value("{spring.datasource.connectionProperties:#{null}}") private String connectionProperties; /** * Druid 鏈接池配置 * * @return */ @Bean @Primary public DataSource dataSource() { DruidDataSource datasource = new DruidDataSource(); datasource.setUrl(this.dbUrl); datasource.setUsername(username); datasource.setPassword(password); datasource.setDriverClassName(driverClassName); //configuration if (initialSize != null) { datasource.setInitialSize(initialSize); } if (minIdle != null) { datasource.setMinIdle(minIdle); } if (maxActive != null) { datasource.setMaxActive(maxActive); } if (maxWait != null) { datasource.setMaxWait(maxWait); } if (timeBetweenEvictionRunsMillis != null) { datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); } if (minEvictableIdleTimeMillis != null) { datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); } if (validationQuery != null) { datasource.setValidationQuery(validationQuery); } if (testWhileIdle != null) { datasource.setTestWhileIdle(testWhileIdle); } if (testOnBorrow != null) { datasource.setTestOnBorrow(testOnBorrow); } if (testOnReturn != null) { datasource.setTestOnReturn(testOnReturn); } if (poolPreparedStatements != null) { datasource.setPoolPreparedStatements(poolPreparedStatements); } if (maxPoolPreparedStatementPerConnectionSize != null) { datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize); } if (connectionProperties != null) { datasource.setConnectionProperties(connectionProperties); } List<Filter> filters = new ArrayList<>(); filters.add(statFilter()); filters.add(wallFilter()); datasource.setProxyFilters(filters); return datasource; } /** * 註冊 servlet * * @return */ @Bean public ServletRegistrationBean druidServlet() { ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); //控制檯管理用戶,加入下面2行 進入druid後臺就須要登陸 servletRegistrationBean.addInitParameter("loginUsername", "admin"); servletRegistrationBean.addInitParameter("loginPassword", "admin"); return servletRegistrationBean; } /** * 註冊 filter * * @return */ @Bean public FilterRegistrationBean filterRegistrationBean() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); filterRegistrationBean.setFilter(new WebStatFilter()); filterRegistrationBean.addUrlPatterns("/*"); filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); filterRegistrationBean.addInitParameter("profileEnable", "true"); return filterRegistrationBean; } @Bean public StatFilter statFilter() { StatFilter statFilter = new StatFilter(); //slowSqlMillis用來配置SQL慢的標準,執行時間超過slowSqlMillis的就是慢。 statFilter.setLogSlowSql(true); //SQL合併配置 statFilter.setMergeSql(true); //slowSqlMillis的缺省值爲3000,也就是3秒。 statFilter.setSlowSqlMillis(1000); return statFilter; } @Bean public WallFilter wallFilter() { WallFilter wallFilter = new WallFilter(); //容許執行多條SQL WallConfig config = new WallConfig(); config.setMultiStatementAllow(true); wallFilter.setConfig(config); return wallFilter; } }
通用Mapper插件網址:https://github.com/abel533/Mapperjava
能夠放在 utils包中mysql
public interface MyMapper<T> extends Mapper<T>, MySqlMapper<T> { //FIXME 特別注意,該接口不能被掃描到,不然會出錯 }
這裏實現一個本身的接口,繼承通用的mapper,關鍵點就是這個接口不能被掃描到,不能跟dao這個存放mapper文件放在一塊兒。
最後在啓動類中經過MapperScan註解指定掃描的mapper路徑:git
@SpringBootApplication @EnableTransactionManagement // 啓註解事務管理,等同於xml配置方式的 <tx:annotation-driven /> @MapperScan(basePackages = "com.dudu.dao", markerInterface = MyMapper.class) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
mybatis-generator.xml文件,該配置文件用來自動生成表對應的Model,Mapper以及xml,該文件位於src/main/resources下面github
Mybatis Geneator 詳解: http://blog.csdn.net/isea533/article/details/42102297spring
<?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> <!--加載配置文件,爲下面讀取數據庫信息準備--> <properties resource="application.properties"/> <context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat"> <plugin type="tk.mybatis.mapper.generator.MapperPlugin"> <!-- 自定義通用 mapper 接口--> <property name="mappers" value="com.dudu.util.MyMapper"/> <!-- caseSensitive 默認false,當數據庫表名區分大小寫時,能夠將該屬性設置爲true--> <property name="caseSensitive" value="true"/> </plugin> <!-- 阻止生成自動註釋 --> <commentGenerator> <property name="javaFileEncoding" value="UTF-8"/> <property name="suppressDate" value="true"/> <property name="suppressAllComments" value="true"/> </commentGenerator> <!--數據庫連接地址帳號密碼--> <jdbcConnection driverClass="${spring.datasource.driver-class-name}" connectionURL="${spring.datasource.url}" userId="${spring.datasource.username}" password="${spring.datasource.password}"> </jdbcConnection> <javaTypeResolver> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <!--生成Model類存放位置--> <javaModelGenerator targetPackage="com.dudu.domain" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> <property name="trimStrings" value="true"/> </javaModelGenerator> <!--生成映射文件存放位置--> <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"> <property name="enableSubPackages" value="true"/> </sqlMapGenerator> <!--生成Dao類存放位置--> <!-- 客戶端代碼,生成易於使用的針對Model對象和XML配置文件 的代碼 type="ANNOTATEDMAPPER",生成Java Model 和基於註解的Mapper對象 type="XMLMAPPER",生成SQLMap XML文件和獨立的Mapper接口 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.dudu.dao" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> </javaClientGenerator> <!--生成對應表及類名 去掉Mybatis Generator生成的一堆 example --> <table tableName="LEARN_RESOURCE" domainObjectName="LearnResource" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"> <generatedKey column="id" sqlStatement="Mysql" identity="true"/> </table> </context> </generatorConfiguration>
其中tk.mybatis.mapper.generator.MapperPlugin很重要,用來指定通用Mapper對應的文件,這樣咱們生成的mapper都會繼承這個通用Mappersql
domain數據庫
@Table(name = "learn_resource") public class LearnResource { /** * ID */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; /** * 做者 */ private String author; /** * 描述 */ private String title; /** * 地址連接 */ private String url; /** * 獲取ID * * @return id - ID */ public Long getId() { return id; } /** * 設置ID * * @param id ID */ public void setId(Long id) { this.id = id; } /** * 獲取做者 * * @return author - 做者 */ public String getAuthor() { return author; } /** * 設置做者 * * @param author 做者 */ public void setAuthor(String author) { this.author = author == null ? null : author.trim(); } /** * 獲取描述 * * @return title - 描述 */ public String getTitle() { return title; } /** * 設置描述 * * @param title 描述 */ public void setTitle(String title) { this.title = title == null ? null : title.trim(); } /** * 獲取地址連接 * * @return url - 地址連接 */ public String getUrl() { return url; } /** * 設置地址連接 * * @param url 地址連接 */ public void setUrl(String url) { this.url = url == null ? null : url.trim(); } }
dao mapperapache
public interface LearnResourceMapper extends MyMapper<LearnResource> { /** * 自定義新增接口 * * @param map * @return */ List<LearnResource> queryLearnResouceList(Map<String, Object> map); }
mapper xmljson
<?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="com.dudu.dao.LearnResourceMapper"> <resultMap id="BaseResultMap" type="com.dudu.domain.LearnResource"> <!-- WARNING - @mbg.generated --> <id column="id" jdbcType="BIGINT" property="id"/> <result column="author" jdbcType="VARCHAR" property="author"/> <result column="title" jdbcType="VARCHAR" property="title"/> <result column="url" jdbcType="VARCHAR" property="url"/> </resultMap> <!--自定義新增接口--> <select id="queryLearnResouceList" resultType="com.dudu.domain.LearnResource"> SELECT * from learn_resource where 1=1 <if test="author != null and author!= ''"> and author like CONCAT('%',#{author},'%') </if> <if test="title != null and title!= ''"> and title like CONCAT('%',#{title},'%') </if> order by id desc </select> </mapper>
通用 service 定義:
具體能夠查看這裏瞭解:https://gitee.com/free/Mapper2/blob/master/wiki/mapper/4.Spring4.md
/** * 通用接口 */ @Service public interface IService<T> { T selectByKey(Object key); int save(T entity); int delete(Object key); int updateAll(T entity); int updateNotNull(T entity); List<T> selectByExample(Object example); //TODO 其餘... } /** * 通用Service 實現 * * @param <T> */ public abstract class BaseService<T> implements IService<T> { @Autowired protected Mapper<T> mapper; public Mapper<T> getMapper() { return mapper; } @Override public T selectByKey(Object key) { //說明:根據主鍵字段進行查詢,方法參數必須包含完整的主鍵屬性,查詢條件使用等號 return mapper.selectByPrimaryKey(key); } @Override public int save(T entity) { //說明:保存一個實體,null的屬性也會保存,不會使用數據庫默認值 return mapper.insert(entity); } @Override public int delete(Object key) { //說明:根據主鍵字段進行刪除,方法參數必須包含完整的主鍵屬性 return mapper.deleteByPrimaryKey(key); } @Override public int updateAll(T entity) { //說明:根據主鍵更新實體所有字段,null值會被更新 return mapper.updateByPrimaryKey(entity); } @Override public int updateNotNull(T entity) { //根據主鍵更新屬性不爲null的值 return mapper.updateByPrimaryKeySelective(entity); } @Override public List<T> selectByExample(Object example) { //說明:根據Example條件進行查詢 //重點:這個查詢支持經過Example類指定查詢列,經過 selectProperties方法指定查詢列 return mapper.selectByExample(example); } } // 具體業務的 service 接口 public interface LearnService extends IService<LearnResource> { List<LearnResource> queryLearnResouceList(Page<LeanQueryLeanListReq> page); void deleteBatch(Long[] ids); } // 具體業務的 service 實現接口 @Service public class LearnServiceImpl extends BaseService<LearnResource> implements LearnService { @Autowired private LearnResourceMapper learnResourceMapper; @Override public void deleteBatch(Long[] ids) { Arrays.stream(ids).forEach(id -> learnResourceMapper.deleteByPrimaryKey(id)); } @Override public List<LearnResource> queryLearnResouceList(Page<LeanQueryLeanListReq> page) { PageHelper.startPage(page.getPage(), page.getRows()); return learnResourceMapper.queryLearnResouceList(page.getCondition()); } }
@Controller @RequestMapping("/learn") public class LearnController extends AbstractController { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private LearnService learnService; @RequestMapping("") public String learn(Model model) { model.addAttribute("ctx", getContextPath() + "/"); return "learn-resource"; } /** * 查詢教程列表 * * @param page * @return */ @RequestMapping(value = "/queryLeanList", method = RequestMethod.POST) @ResponseBody public AjaxObject queryLearnList(Page<LeanQueryLeanListReq> page) { List<LearnResource> learnList = learnService.queryLearnResouceList(page); PageInfo<LearnResource> pageInfo = new PageInfo<LearnResource>(learnList); return AjaxObject.ok().put("page", pageInfo); } /** * 新添教程 * * @param learn */ @RequestMapping(value = "/add", method = RequestMethod.POST) @ResponseBody public AjaxObject addLearn(@RequestBody LearnResource learn) { learnService.save(learn); return AjaxObject.ok(); } /** * 修改教程 * * @param learn */ @RequestMapping(value = "/update", method = RequestMethod.POST) @ResponseBody public AjaxObject updateLearn(@RequestBody LearnResource learn) { learnService.updateNotNull(learn); return AjaxObject.ok(); } /** * 刪除教程 * * @param ids */ @RequestMapping(value = "/delete", method = RequestMethod.POST) @ResponseBody public AjaxObject deleteLearn(@RequestBody Long[] ids) { learnService.deleteBatch(ids); return AjaxObject.ok(); } } ** * 前臺傳的分頁參數 分頁工具類 * * @param <T> */ public class Page<T> implements Serializable { private int page; //當前頁 private int rows; //每頁多少條 private static final long serialVersionUID = 1L; private List<T> records = Collections.emptyList(); private Map<String, Object> condition; public int getPage() { return page; } public void setPage(int page) { this.page = page; } public int getRows() { return rows; } public void setRows(int rows) { this.rows = rows; } public static long getSerialVersionUID() { return serialVersionUID; } public List<T> getRecords() { return records; } public void setRecords(List<T> records) { this.records = records; } public Map<String, Object> getCondition() { return condition; } public void setCondition(Map<String, Object> condition) { this.condition = condition; } }
10:30:10.818 logback [http-nio-8090-exec-3] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Read [class [Ljava.lang.Long;] as "application/json;charset=UTF-8" with [com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter@3b22e32f] 10:30:10.822 logback [http-nio-8090-exec-3] DEBUG o.s.t.a.AnnotationTransactionAttributeSource - Adding transactional method 'com.dudu.service.impl.LearnServiceImpl.deleteBatch' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '' 10:30:10.822 logback [http-nio-8090-exec-3] DEBUG o.s.j.d.DataSourceTransactionManager - Creating new transaction with name [com.dudu.service.impl.LearnServiceImpl.deleteBatch]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '' 10:30:10.822 logback [http-nio-8090-exec-3] DEBUG o.s.j.d.DataSourceTransactionManager - Acquired Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5f82a880] for JDBC transaction 10:30:10.822 logback [http-nio-8090-exec-3] DEBUG o.s.j.d.DataSourceTransactionManager - Switching JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5f82a880] to manual commit 10:30:10.830 logback [http-nio-8090-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - **Creating a new SqlSession** 10:30:10.831 logback [http-nio-8090-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5454410e] 10:30:10.833 logback [http-nio-8090-exec-3]**DEBUG o.m.s.t.SpringManagedTransaction - JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5f82a880] will be managed by Spring** 10:30:10.833 logback [http-nio-8090-exec-3] DEBUG c.d.d.L.deleteByPrimaryKey - ==> Preparing: DELETE FROM learn_resource WHERE id = ? 10:30:10.848 logback [http-nio-8090-exec-3] DEBUG c.d.d.L.deleteByPrimaryKey - ==> Parameters: 1031(Long) 10:30:10.850 logback [http-nio-8090-exec-3] DEBUG c.d.d.L.deleteByPrimaryKey - <== Updates: 1 10:30:10.850 logback [http-nio-8090-exec-3] DEBUG c.a.druid.pool.PreparedStatementPool - {conn-10005, pstmt-20002} enter cache 10:30:10.850 logback [http-nio-8090-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5454410e] 10:30:10.850 logback [http-nio-8090-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5454410e] 10:30:10.850 logback [http-nio-8090-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5454410e] 10:30:10.850 logback [http-nio-8090-exec-3] DEBUG org.mybatis.spring.SqlSessionUtils - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5454410e] 10:30:10.850 logback [http-nio-8090-exec-3] DEBUG o.s.j.d.DataSourceTransactionManager - Initiating transaction commit 10:30:10.850 logback [http-nio-8090-exec-3] **DEBUG o.s.j.d.DataSourceTransactionManager - Committing JDBC transaction on Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5f82a880]** 10:30:10.852 logback [http-nio-8090-exec-3] DEBUG o.s.j.d.DataSourceTransactionManager - Releasing JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@5f82a880] after transaction 10:30:10.852 logback [http-nio-8090-exec-3] DEBUG o.s.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource